[
  {
    "path": "LICENSE.md",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   Copyright 2017 California Institute of Technology\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n\n=======================================================================\n\nFDT Libraries:\n\nFDT project contains libraries with separate copyright notices\nand license terms. Your use of the source code for the these\nlibraries is subject to the terms and conditions of the following\nlicenses.\n\n========================================================================\n\nAcknowledgement:\n\nCopyright 2017 California Institute of Technology, based on research sponsored\nand supported by the DOE Office of High Energy Physics, the DOE Office of Advanced\nScientific Computing, the NSF Mathematical and Physical Sciences and Directorate,\nand the NSF Division of Advanced Cyberinfrastructure.\n"
  },
  {
    "path": "LICENSE_GANYMED_SSH2.txt",
    "content": "Copyright (c) 2005 - 2006 Swiss Federal Institute of Technology (ETH Zurich),\r\n  Department of Computer Science (http://www.inf.ethz.ch),\r\n  Christian Plattner. All rights reserved.\r\n\r\nRedistribution and use in source and binary forms, with or without\r\nmodification, are permitted provided that the following conditions\r\nare met:\r\n\r\na.) Redistributions of source code must retain the above copyright\r\n    notice, this list of conditions and the following disclaimer.\r\nb.) Redistributions in binary form must reproduce the above copyright\r\n    notice, this list of conditions and the following disclaimer in the\r\n    documentation and/or other materials provided with the distribution.\r\nc.) Neither the name of ETH Zurich nor the names of its contributors may\r\n    be used to endorse or promote products derived from this software\r\n    without specific prior written permission.\r\n\r\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\r\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\r\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r\nPOSSIBILITY OF SUCH DAMAGE.\r\n\r\n\r\nThe Java implementations of the AES, Blowfish and 3DES ciphers have been\r\ntaken (and slightly modified) from the cryptography package released by\r\n\"The Legion Of The Bouncy Castle\".\r\n\r\nTheir license states the following:\r\n\r\nCopyright (c) 2000 - 2004 The Legion Of The Bouncy Castle\r\n(http://www.bouncycastle.org)\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof this software and associated documentation files (the \"Software\"), to deal\r\nin the Software without restriction, including without limitation the rights\r\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\ncopies of the Software, and to permit persons to whom the Software is\r\nfurnished to do so, subject to the following conditions:\r\n\r\nThe above copyright notice and this permission notice shall be included in\r\nall copies or substantial portions of the Software.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\nTHE SOFTWARE. \r\n\r\n"
  },
  {
    "path": "MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nClass-Path: io-2.2.0.jar bcprov-jdk15on-157.jar gss-2.2.0.jar gram-2.2.0.jar jsse-2.2.0.jar\n axisg-2.2.0.jar gridftp-2.2.0.jar myproxy-2.2.0.jar commons-io-2.4.jar\n  commons-logging.jar commons-codec-1.7.jar commons-lang3-3.1.jar ssl-\n proxies-2.2.0.jar io-2.2.0.jar gss-2.2.0.jar gram-2.2.0.jar jsse-2.2.\n 0.jar axisg-2.2.0.jar gridftp-2.2.0.jar myproxy-2.2.0.jar commons-io-\n 2.4.jar commons-logging.jar commons-codec-1.7.jar commons-lang3-3.1.j\n ar ssl-proxies-2.2.0.jar BCGSS.jar ShiFT.jar SSHVnc.jar filedrop.jar \n libbrowser.jar log4j-1.2.6.jar SSHTerm-1.0.0.jar jlirc-unix-soc.jar p\n utty-pk-1.1.0.jar SecureTunneling.jar bcprov-jdk16-146.jar j2ssh-core\n -0.2.7.jar ncsa-lcrypto-146.jar TransferAPIClient.jar j2ssh-common-0.\n 2.7.jar swing-layout-1.0.3.jar voms-api-java-2.0.9.jar commons-compre\n ss-1.2.jar not-yet-commons-ssl-0.3.11.jar BCGSS.jar ShiFT.jar SSHVnc.\n jar filedrop.jar libbrowser.jar log4j-1.2.6.jar SSHTerm-1.0.0.jar jli\n rc-unix-soc.jar putty-pk-1.1.0.jar SecureTunneling.jar j2ssh-core-0.2\n .7.jar ncsa-lcrypto-146.jar TransferAPIClient.jar j2ssh-common-0.2.7.\n jar swing-layout-1.0.3.jar voms-api-java-2.0.9.jar commons-compress-1\n .2.jar not-yet-commons-ssl-0.3.11.jar io-2.2.0.jar gss-2.2.0.jar gram\n -2.2.0.jar jsse-2.2.0.jar axisg-2.2.0.jar gridftp-2.2.0.jar myproxy-2\n .2.0.jar commons-io-2.4.jar commons-logging.jar commons-codec-1.7.jar\n  commons-lang3-3.1.jar ssl-proxies-2.2.0.jar bcprov-jdk15on-157.jar\nMain-Class: lia.util.net.copy.FDTMain\n\n"
  },
  {
    "path": "README",
    "content": "\nFDT uses third-party libraries which are not distributed with this source code.\n\nPlease check the Security section on the FDT web page if you want to compile this source code:\nhttp://monalisa.cern.ch/FDT/documentation_security.html\n\nSimple examples for user filters can be found under:\nsrc/lia/util/net/copy/filters/examples directory\n\nFor any features, suggestions or bug reports please contact: support-fdt@monalisa.cern.ch\n\n"
  },
  {
    "path": "README.md",
    "content": "FDT is an Application for Efficient Data Transfers which is capable of reading and writing at disk speed over wide area networks (with standard TCP). It is written in Java, runs an all major platforms and it is easy to use.\n\nFDT is based on an asynchronous, flexible multithreaded system and is using the capabilities of the Java NIO libraries. Its main features are:\n\nStreams a dataset (list of files) continuously, using a managed pool of buffers through one or more TCP sockets.\nUses independent threads to read and write on each physical device\nTransfers data in parallel on multiple TCP streams, when necessary\nUses appropriate-sized buffers for disk I/O and for the network\nRestores the files from buffers asynchronously\nResumes a file transfer session without loss, when needed\nFDT can be used to stream a large set of files across the network, so that a large dataset composed of thousands of files can be sent or received at full speed, without the network transfer restarting between files.\n\n[MORE...](https://fast-data-transfer.github.io/fdt/)\n\n![alt tag](http://monalisa.cern.ch/FDT/img/FDT_diagram.png)\n"
  },
  {
    "path": "add-lib-to-local-maven.sh",
    "content": "#!/usr/bin/env bash\n# Adding lib directory contents to a local maven repository then later we could use them in fdt building\n# Maven should be installed already on machine (i.e. use sudo apt-get install maven)\n\n#Globus dependencies\nmvn install:install-file -Dfile=\"lib/globus/gss-2.2.0.jar\" -DgroupId=org.globus.gsi.gssapi -DartifactId=gss -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/io-2.2.0.jar\" -DgroupId=org.globus.io -DartifactId=io -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/jsse-2.2.0.jar\" -DgroupId=org.globus.jsse -DartifactId=jsse -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/myproxy-2.2.0.jar\" -DgroupId=org.globus.myproxy -DartifactId=myproxy -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/ssl-proxies-2.2.0.jar\" -DgroupId=org.globus -DartifactId=ssl-proxies -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/gridftp-2.2.0.jar\" -DgroupId=org.globus -DartifactId=gridftp -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/gram-2.2.0.jar\" -DgroupId=org.globus -DartifactId=gram -Dversion=2.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/globus/axisg-2.2.0.jar\" -DgroupId=org.globus -DartifactId=axisg -Dversion=2.2.0 -Dpackaging=jar\n# END of Globus dependencies\n\n#SSH Tools dependencies\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/TransferAPIClient.jar\" -DgroupId=org.globusonline -DartifactId=TransferAPIClient -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/SSHVnc.jar\" -DgroupId=com.sshtools.sshvnc -DartifactId=SSHVnc -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/SSHTerm-1.0.0.jar\" -DgroupId=com.sshtools.sshterm -DartifactId=SSHTerm -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/ShiFT.jar\" -DgroupId=com.sshtools.shift -DartifactId=ShiFT -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/putty-pk-1.1.0.jar\" -DgroupId=com.sshtools.ext -DartifactId=putty-pk -Dversion=1.1.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/SecureTunneling.jar\" -DgroupId=com.sshtools.tunnel -DartifactId=SecureTunneling -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/not-yet-commons-ssl-0.3.11.jar\" -DgroupId=org.apache.commons -DartifactId=not-yet-commons-ssl -Dversion=0.3.11 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/ncsa-lcrypto-146.jar\" -DgroupId=edu.illinois.ncsa -DartifactId=ncsa-lcrypto -Dversion=1.4.6 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/libbrowser.jar\" -DgroupId=uk.ac.rl.esc.browser -DartifactId=libbrowser -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/jlirc-unix-soc.jar\" -DgroupId=org.lirc.socket -DartifactId=jlirc-unix-soc -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/j2ssh-core-0.2.7.jar\" -DgroupId=com.sshtools.core -DartifactId=j2ssh-core -Dversion=0.2.7 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/j2ssh-common-0.2.7.jar\" -DgroupId=com.sshtools.common -DartifactId=j2ssh-common -Dversion=0.2.7 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/filedrop.jar\" -DgroupId=net.iharder.dnd -DartifactId=filedrop -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/commons-compress-1.2.jar\" -DgroupId=org.apache.commons -DartifactId=commons-compress -Dversion=1.2.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/bcprov-jdk15on-1.50.jar\" -DgroupId=org.bouncycastle -DartifactId=bcprov -Dversion=1.50.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/BCGSS.jar\" -DgroupId=edu.illinois.ncsa -DartifactId=BCGSS -Dversion=1.0.0 -Dpackaging=jar\nmvn install:install-file -Dfile=\"lib/gsi-sshterm/swing-layout-1.0.3.jar\" -DgroupId=org.jdesktop -DartifactId=swing-layout -Dversion=1.0.3 -Dpackaging=jar\n#mvn install:install-file -Dfile=\"bbbb\" -DgroupId=aaaaa -DartifactId=BCGSS -Dversion=1.0.0 -Dpackaging=jar\n\nmvn install:install-file -Dfile=\"lib/opentsdb/opentsdb-client-2.1.0.jar\" -DgroupId=org.opentsdb -DartifactId=opentsdb-client -Dversion=2.1.0 -Dpackaging=jar\n\necho \"FINISHED INSTALLING LOCAL DEPENDENCIES\""
  },
  {
    "path": "build-all.sh",
    "content": "#!/usr/bin/env bash\n\nif command -v yum > /dev/null 2>&1; then\n    OS=\"Centos\"\n    CMD=yum\nelif command -v zypper > /dev/null 2>&1; then\n    OS=\"OpenSuse\"\n    CMD=zypper\nelse\n    OS=\"Debian\"\n    CMD=apt-get\nfi\nif command -v mvn > /dev/null 2>&1; then\n    echo \"Maven already installed \"\n    echo \"Detected OS $OS, using command $CMD\"\nelse\n    echo \"Maven will be installed \"\n    sudo $CMD install maven\nfi\necho \"Addling libraries to local maven repository\"\n./add-lib-to-local-maven.sh\n\n\nmvn clean install\n\n"
  },
  {
    "path": "classpath",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<classpath>\n\t<classpathentry kind=\"src\" path=\"src\"/>\n\t<classpathentry kind=\"con\" path=\"org.eclipse.jdt.launching.JRE_CONTAINER\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/jgss.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/cryptix.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/gsi-sshterm/SSHTerm-1.0.0.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/puretls.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/cog-jglobus.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/log4j-1.2.13.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/globus/commons-logging-1.1.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/gsi-sshterm/j2ssh-common-0.2.7.jar\"/>\n\t<classpathentry kind=\"lib\" path=\"lib/gsi-sshterm/j2ssh-core-0.2.7.jar\"/>\n\t<classpathentry kind=\"output\" path=\"build/classes\"/>\n</classpath>\n"
  },
  {
    "path": "docs/_config.yml",
    "content": "title: Fast Data Transfer\ndescription: FDT is an application for efficient data transfers, which is capable of reading and writing at disk speed over wide area networks (with standard TCP). It is written in Java, runs an all major platforms, and it is easy to use.\nshow_downloads: false\ngoogle_analytics:\n  theme: jekyll-theme-cayman\n  gems:\n      - jekyll-menus\n"
  },
  {
    "path": "docs/doc-examples.md",
    "content": "[[Home](index.md)]  [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[[FDT & DDCopy](doc-fdt-ddcopy.md)]   [Examples]   [[Security](doc-security.md)]    [[User's Extensions](doc-user-extensions.md)]    [[System Tuning](doc-system-tuning.md)]    [[FDT Monitoring](doc-opentsdb.md)]\n\n### Examples\n\n1. To send one file called `local.data` from the local system\ndirectory to another computer\nin the `/home/remoteuser/destiantionDir` folder, with default\nparameters, there are two options:\n\n- Client/Server mode\n\nFirst, the FDT server needs to be started on the remote system. (The default settings will be used, which implies the default port, 54321, on both the client and the server). `-S` is used to disable the standalone mode, which means that the server will stop after the session will finish.\n\n```\n[remote computer]$ java -jar fdt.jar -S\n```\n\nThen, the client will be started on the local system specifying the sourcefile, the remote address (or hostname) where the server was started in the previous step and the destination directory\n        \n```\n[local computer]$ java -jar fdt.jar -c <remote_address> -d /home/remoteuser/destinationDir /home/localuser/local.data\n```\n\nOR\n\n```\n[local computer]$ java -jar fdt.jar -c <remote_address> -d destinationDir ./local.data\n```\n\n- Secure Copy (SCP) mode\n\nIn this mode the server will be started on the remote system automatically by the local FDT client using SSH.\n\n```\n[local computer]$ java -jar fdt.jar /home/localuser/local.data remoteuser@<remote_address>:/home/remoteuser/destinationDir\n```\n\nOR\n\n```\n[local computer]$ java -jar fdt.jar ./local.data remoteuser@<remote_address>:destinationDir\n```\n\nIf the `remoteuser` parameter is not specified, the local user, running the `fdt` command, will be used to login on the remote system.\n\n2. To get the content of an entire folder and all its children,\nlocated in the user's home directory, the `-r` ( recursive\nmode ) flag will be specified and also `-pull` to sink the data from the\nserver. In the Client/Server mode the access to the server will be\nrestricted to the local IP addresses only ( with `-f` flag ).\n\n- Client/Server mode\n\nMultiple addresses may be specfied using the `-f` flag using `:`. If the client's IP address(es) is not specified in the allowed IP addresses, the connection will be closed. In the following command the server is started in standalone mode, which means that will continue to run after the session will finish. The transfer rate for every client sessions will be limited to 4 MBytes/s.\n\n```\n[remote computer]$ java -jar fdt.jar -f allowedIP1:allowedIP2 -limit 4M\n```\n\nOR\n\n```\n[remote computer]$ java -jar fdt.jar -f allowedIP1:allowedIP2 -limit 4096K\n```\n\nThe command for the local client will be.\n\n```\n[local computer]$ java -jar fdt.jar -pull -r -c <remote_address> -d /home/localuser/localDir /home/remoteuser/remoteDir\n```\n\nOR\n\n```\n[local computer]$ java -jar fdt.jar -pull -r -c <remote_address> -d localDir remoteDir\n```\n\n- SCP mode\n\nIn this mode only the order of the parameters will be changed, and `-r` is the only argument that must be added (`-pull` is implicit). Same authentication policies apply as in the first example.\n\n```\n[local computer]$ java -jar fdt.jar -r  remoteuser@<remote_address>:/home/remoteuser/remoteDir /home/localuser/localDir\n```\n\nOR\n\n```\n[local computer]$ java -jar fdt.jar -r remoteuser@<remote_address>:remoteDir localDir\n```\n\n3. To test the network connectivity a transfer here is an example\nwhich transfers data from `/dev/zero` to `/dev/null` using 10 streams in\nblocking mode, for both the server and the client with 8 MBytes\nbuffers. The server will stop after the test is finished.\n\n- Client/Server mode\n\n```\n[remote computer]$ java -jar fdt.jar -bio -bs 8M -f allowedIP -S\n```\n\n```\n[local computer]$ java -jar fdt.jar -c <remote_address> -bio -P 10 -d /dev/null /dev/zero\n```\n\n- SCP mode\n\n```\n[local computer]$ java -jar fdt.jar -bio -P 10 /dev/zero remoteAddress:/dev/null\n```\n\n4. The user can also define a file, which contains list of files (a filename per line)\nto be transfered. FDT will detect if the files are located on multiple\ndevices and will use a dedicated thread for each device.\n\n```\n[remote computer]$ java -jar fdt.jar -S\n```\n\n```\n[local computer]$ java -jar fdt.jar -fl ./file_list.txt -c <remote_address> -d /home/remoteuser/destDir\n```\n\n5. To test the local read/write performance of the local disk the\nDDCopy may be used.\n\n- The following command will copy the entire partition\n`/dev/dsk/c0d1p1` to `/dev/null` reporting every 2 seconds ( the default )\nthe I/O speed.\n\n```\n[local computer]$ java -cp fdt.jar lia.util.net.common.DDCopy if=/dev/dsk/c0d1p1 of=/dev/null\n```\n\n- To test the write speed of the file system using a 1GB file\nread from `/dev/zero` the following command may be used. The operating\nsystem will sync() the data to the disk. The data will be read/write\nusing 10MB buffers.\n\n```\n[local computer]$ java -cp fdt.jar lia.util.net.common.DDCopy if=/dev/zero of=/home/user/1GBTestFile bs=10M count=100 flags=NOSYNC\n```\n\nOR\n\n```\n[local computer]$ java -cp fdt.jar lia.util.net.common.DDCopy if=/dev/zero of=/home/user/1GBTestFile bs=1M bn=10 count=100 flags=NOSYNC\n```\n\n- Launching FDT as Agent example:\n\n```\njava -jar fdt.jar -tp <transfer,ports,separated,by,comma> -p <portNo> -agent\n```\n\n- Sending coordinator message to the agent:\n\n```\njava -jar fdt.jar -dIP <destination-ip> -dp <destination-port> -sIP <source-ip> -p <source-port> -d /tmp/destination/files -fl /tmp/file-list-on-source.txt -coord\n```\n- Retrieving session log file. \n\nTo retrieve session log file user needs to provide at least these parameters:\n\n```\njava -jar fdt.jar  -c <source-host> -d /tmp/destination/files -sID <session-ID>\n```\n\n- To retrieve list of files on custom path there is a custom mode which can be used.\n\n```\njava -jar fdt.jar  -c <source-host> -ls /tmp/\n```\n\n\n\n\n"
  },
  {
    "path": "docs/doc-fdt-ddcopy.md",
    "content": "[[Home](index.md)]  [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[FDT & DDCopy]  [[Examples](doc-examples.md)]  [[Security](doc-security.md)]    [[User's Extensions](doc-user-extensions.md)]    [[System Tuning](doc-system-tuning.md)]    [[FDT Monitoring](doc-opentsdb.md)]\n\n### FDT\n**FDT** can be used in one of these seven modes:\n* **Server**: java -jar fdt.jar [ OPTIONS ]\n* **Client**: java -jar fdt.jar [ OPTIONS ] -c \\<host> [file1 ...]|[-fl \\<fileList>] -d \\<destinationDirectory>\n* **SCP**: java -jar fdt.jar [ OPTIONS ] [[[user@][host1:]]file1 [[[user@][host2:]]file2\n* **Coordinator**: java -jar fdt.jar [OPTIONS] -dIP \\<destination-ip> -dp \\<destination-port> -sIP \\<source-ip> -p \\<source-port> -d \\<destinationDirectory>  [-fl \\<fileList>] -coord\n* **List Files**: java -jar fdt.jar [OPTIONS] -c \\<host> -ls \\<ls-path>\n* **Agent**: java -jar fdt.jar [OPTIONS] -c \\<host>  -tp \\<transfer,ports,separated,with,comma> -agent \n* **Session log**: java -jar fdt.jar [OPTIONS] -c \\<host> -d \\<destinationDirectory> -sID \\<session-ID>\n\nIn Server mode the FDT will start listening for incoming client connections. The server may or may not stop after the last client finishes the transfer. In Client mode the client will connect to the specified host, where an FDT Server is expected to be running. The client can either read or write file from/to the server. \n\nIn the SCP (Secure Copy) mode the local FDT instance will use SSH to start/stop the FDT server and/or client. The security is based on ssh credentials. The server started in this mode will accept connections **ONLY** from the \"SCP\" client. It is possible to restrict the access for the FDT Servers started from the command line using the `-f` option. The option accepts a list of IP addresses separated by `:`. \n\nIn order to use third party copy feature with FDT there have to be two FDT launched in agent mode. In Agent mode the FDT will start listening for incoming client connections on. In Agent mode the client will listen for coordinator message with task. After receiving coordinator message Agent will try to send message to destination Agent requesting to open socket for transfer session. Destination Agent will take one transfer port from pool and open port for that session and then informs source Agent that transfer job can be started. At this pont first agent now has session ID and it sends it to the coordinator, that later coordinator could see that FDT session log file from remote Agent. After finishing task Agent will close transfer port and return it to the transfer ports pool.\n\nTo retrieve list of files on custom path there is a custom mode which can be used. User needs to specify host and port (if not default) and specify path from where he want to get list of files. It will not list files in directory where he has no access.\n\nThe OPTIONS currently supported may be server or client specific, or may be used in both modes.\n\n**Common  options used for both server and client :**\n\n**-gsi** enables GSI authentication scheme in FDT. When started in server mode the FDT will open two TCP ports: one for GSI authentication and the other one for data channels\n\n**-gsip \\<GSICtrlPort>** specifies the TCP port used for GSI authentication. Default value is 54320.\n\n**-p \\<portNo>** specifies the TCP port to be used (for the server it is the port used to listen on; for the client the port to connect to). The default port is 54321.\n\n**-preFilters f1,...,fn** User defined preProcessing filters. The classes specified by the f1,...,fn paramenters must be in the classpath. The prePRocessing filters must be defined in the FDT \"sender\" command line. Please see the User's Filters section for more details and examples.\n\n**-postFilters f1,...,fn** User defined postProcessing filters. The classes specified by the f1,...,fn paramenters must be in the classpath. The postPRocessing filters must be defined in the FDT \"receiver\" command line. Please see the User's Filters section for more details and examples.\n\n**-bio** Blocking I/O mode. n this mode every channel (socket) will be configured to send/receive data synchronously and FDT will use one thread per channel. By default, non-blocking I/O will be used. On some platforms/systems the throughtput can be slightly higher in blocking I/O mode. The limitation in the blocking mode is the maximum number of threads that can be used and, for very high numbers of streams (thousands), the CPU used by the kernel for scheduling the threads. By default, FDT will use non-blocking mode.\n\n**-iof \\<iof>** Non-blocking I/O retry factor. In non-blocking mode every read/write operation which returns 0, will be repeated up to <iof> times before waiting for I/O readiness. By default this value is set to 1, which means that every network read/write operation will return in the select() (which can also be poll()/epoll()) if no more data can be processed by the underlying channel(socket). The default value should work fine on most of the systems, but values of 2 or 3, may increase the throughput on some systems. Values higher than 5 will only increase the CPU system usage, without any gain in performance. \n\n**-limit \\<rate>** Restrict the transfer speed at the specified rate. K (KiloBytes/s), M (MegaBytes/s) or G (GigaBytes/s) may be used as suffixes. When this parameter is specified in the server it represents the maximum transfer rate for every FDT session. If the parameter is specified in both the server and the client, the minimum value between them will be used.\n\n**-md5** Enables MD5 checksum for every file involved in the transfer. The flag may be specified for both client and server, but it will be used by the \"sender\" session only. When the transfer finishes the list will be sent to the \"receiver\" and it will be printed in a `md5sum`-like mode\n\n**-printStats** Various statistics about buffer pools, sessions, etc will be printed\n\n**-v** Verbose. Multiple 'v'-s (up to three) may be used to increment the verbosity level. Maximum level is three (-vvv) which corresponds to Level.FINEST for the standard Java logging system used by FDT.\n\n**-u, -update** Update. If a newer version of fdt.jar is available on the update server it will update the local copy \n\n**Server options :**\n\n**-S** disable the standalone mode; when specified the FDT Server will stop after the last client finishes. By default, the server will continue to listen for incoming clients. This option is automatically passed to the server started in \"SCP\" mode. \n\n**-bs \\<buffSize>** Size for the I/O buffers. K (KiloBytes) or M (MegaBytes) may be used as suffixes. The default value is 512K. If the number of clients or sockets is expected to be very high is better to decrease this value. The memory used by this buffers is directly mapped in the operating system memory pages. The memory used by this buffers is limited by the JVM and can be increased passing -XX:MaxDirectMemorySize=<X>m (e.g -XX:MaxDirectMemorySize=256m) to the 'java' command\n\n**-f \\<allowedIPsList>** A list of IP addresses allowed to connect to the server. Multiple IPs may be specified, separated by ':'\n\n**Client options :**\n\n**-c \\<host>** connect to the specified host. If this parameter is missing the FDT will become server\n\n**-gsissh** used in the Secure Copy Mode to specify GSI authentication instead of normal SSH authentication scheme. The remote sshd servere must support GSI authentication. \n\n**-d \\<dstDir>** The destination directory used to copy files. \n\n**-fl \\<fileList>** a file which contains a list of files. Must have only one file per line. \n\n**-pull** Pull mode. The client will receive the data from the server. \n\n**-N** disable Nagle algorithm \n\n**-ss \\<wsz>** Set the TCP SO_SND_BUFFER size. M and K may be used as suffixes for Kilo/Mega. \n\n**-P \\<noOfStreams>** Number of paralel streams to use. Default is 4.\n\n**Common options used for FDT Agent mode :**\n\nAgent can use booth Server and Client options too, because at any time Agent can be Server or Client\n\n**-p \\<portNo>** specifies the TCP port to be used (for the server it is the port used to listen on; for the client the port to connect to). The default port is 54321.\n\n**-tp \\<transfer-ports>** specifies the TCP port lis to be used for transfer sessions. Ports are separated with comma.\n\n**-agent** Option for FDT to run as agent.\n\n**Common options used for FDT Coordinator mode :**\n\n**-d \\<dstDir>** The destination directory used to copy files. \n\n**-fl \\<fileList>** a list of files. Must have only one file per line. \n\n**-dIP \\<destination-ip>** destination Agent IP address.\n\n**-sIP \\<source-ip>** source Agent IP address.\n\n**-dp \\<destination-port>** destination agent message channel port.\n\n**-p \\<source-port>** source agent message channel port.\n\n**-coord** Option for FDT to run as coordinator.\n\n**Common options used for FDT List Files mode :**\n\n**-c \\<host>** connect to the specified host. If this parameter is missing the FDT will become server\n\n**-ls \\<ls-path>** path from where user wants to see lits of files\n\n**Common options used for FDT Session log file retrieving mode :**\n\n**-c \\<host>** connect to the specified host. If this parameter is missing the FDT will become server\n\n**-sID \\<session-id>** session ID retrieved from coordinator.\n\n**-d \\<dstDir>** The destination directory used to copy session log file.\n\n**Options used for FDT monitoring to OpenTSDB:**\n\n**-opentsdb \\<opentsdb-ip:port>** OpenTSDB server and port where FDT will send metrics\n\n**-fdtTAG \\<tag>** custom FDT metrics tag \n\n**-FDT_LISTEN \\<IP>** listen only to specific IP address\n\n\t\n### DDCopy\n**DDCopy** is very similar to Unix `dd` command and can be used to test the local disks or file system. It is bundled in the fdt.jar and has the following syntax:\n\njava -cp fdt.jar lia.util.net.common.DDCopy [ OPTIONS ] **if=\\<sourceFile> of=\\<destinationFile>**\n\nwhere OPTIONS may be:\n\n**bs=\\<BufferSize>**     size of the buffer used for read/write. K or M (for KiloBytes/MegaBytes) may be used as suffixes. Default is 4K\n\n**bn=\\<NoOfBuffers>**     Number of buffers used to readv()/writev() at once. If this parameter is 1, or is missing DDCopy will read()/write() a single buffer at a time, otherwise the readv()/writev() will be used. Default is 1\n\n**count=\\<count>**        Number of \"blocks\" to write. A \"block\" is represents how much data is read/write. The size of a \"block\" is: <BufferSize>*<BuffersNumber>. If <count> <= 0 the copy stops when EOF is reached reading the <SourceFile>. The default is 0\n\n**statsdelay=\\<seconds>**  Number of seconds between intermediate reports. Default is 2 seconds. If <seconds> <= 0 no intermediate reports will be printed\n\n**flags=\\<flag>**          The <flag> field can have of the following values:\n                          **SYNC**    For every write both data and metadata are written synchronously\n                          **DSYNC**  Same as SYNC, but only the data is written synchronously.\n                          **NOSYNC** The sync() is left to be done by the underlying OS\n                         The default value is **DSYNC**\n\n**rformat=\\<rformat>**     Report format. Possible values are:\n                            K - KiloBytes\n                            M - MegaBytes\n                            G - GigaBytes\n                            T - TeraBytes\n                            P - PetaBytes\n                         The default value is self adjusted. If the factor is too big only 0s will be displayed.\n"
  },
  {
    "path": "docs/doc-opentsdb.md",
    "content": "[[Home](index.md)]   [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[[FDT & DDCopy](doc-fdt-ddcopy.md)]   [[Examples](doc-examples.md)]   [[Security](doc-security.md)]   [[User's Extensions](doc-user-extensions.md)]    [[System Tuning](doc-system-tuning.md)]    [ FDT Monitoring ]\n\n### FDT Monitoring\nFDT provides self monitoring possibility. FDT can send metrics to the OpenTSDB server and these metrics can be used to draw FDT dashboard using Grafana tool.\n\nIn order to start monitoring and sending metrics to OpenTSDB server user has to specify OpenTSDB server address and port number for FDT using commandline argument *-opentsdb*\nOptional parameter is *-fdtTAG* which allows user to specify cistom tag for all metrics from that specific FDT.\nIf user is using proxy server then additional Java arguments has to be passed to provide proxy host and proxy port. \nAt this moment no authentication is implemented for proxy and OpenTSDB.\n\n#### Examples\n\n*Monitor net test metrics to specified OpenTSDB server:*\n\nSERVER2\n```\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest\n```\nSERVER1\n```\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2\n```\n*Monitor net test metrics to specified OpenTSDB server with specific tag:*\nSERVER2\n```\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -fdtTAG <tag>\n```\nSERVER1\n```\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2 -fdtTAG <tag>\n```\n*Monitor net test metrics to specified OpenTSDB server and using http proxy server:*\nSERVER2\n```\njava -Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port> -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest\n```\nSERVER1\n```\njava -Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port> -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2\n```\n"
  },
  {
    "path": "docs/doc-security.md",
    "content": "[[Home](index.md)]   [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[[FDT & DDCopy](doc-fdt-ddcopy.md)]   [[Examples](doc-examples.md)]   [Security]   [[User's Extensions](doc-user-extensions.md)]    [[System Tuning](doc-system-tuning.md)]    [[FDT Monitoring](doc-opentsdb.md)]\n\n### FDT Security\nFDT provides several security schemes to allow sending and receiving files over public networks.\nThe FDT architecture allows to \"plug-in\" external security APIs and to use them for client authentication and authorization. The current version supports:\n\n* SSH channels\n\n* GSI-SSH [ NGS GSI-SSHTerm: http://www.grid-support.ac.uk/content/view/81/62/ ]\n\n* Globus-GSI [CoG JGlobus: http://dev.globus.org/wiki/CoG_JGlobus_1.4 ]\n\n`Please note that FDT distribution does not include these security packages. The user should download the libraries for preferred API from its source. See below the instructions to install different security libraries.`\n\nThere are four security modes that one can set when transferring files with FDT:\n##### **1. Source IP address filtering**\n\nIn this mode the server activates a simple IP-based firewall where each source IP is checked against the list of allowed IPs. In this mode no user authentication is done.\n\nBy default FDT starts allowing clients from any destination.\n\nTo enable this mode, pass the \"-f\" option when starting FDT server:\n-f <allowedIPsList> , where allowedIPsList: A list of IP addresses allowed to connect to the server. \nMultiple IP addresses may be separated by ':'.\nYou can use CIDR notation to specify an entire subnet.\n    \n`However, please note that this mode does not enable any privacy or confidentiality on client-server control channel and it may be subject to source IP spoofing.`\n\nIP filtering can be used together with other authentication schemes.\n\n##### **2. Using SSH channels to securely start remote FDT client/server**\nThis mode is enabled when you use \"SCP syntax\" to transfer files with FDT. In this mode the local client starts on-the-fly an instance of FDT server, using an SSH connection to pass the start-up command to the remote machine. It is required the server system runs a ssh demon and the user has a valid shell account. The FDT server will accept data connections from only this client and will exit when the transfer finishes.\nWhen both the source and destination are remote (i.e. the client uses a third-party machine to initiate the transfer) a different SSH connection is made for the client and server in order to start them on the specified machines. (the remote hosts should already have running an OpenSSH compatible SSH server).\nDuring the transfer, the control channels with the remote hosts are kept open and the status messages are streamed back to the user console.\n\nExample:\nUsing local FDT client to transfer files to/from remote hosts:\n\n```\nfdt /path/to/file1 user@hostname:/path/to/file2\n```\n\n```\nfdt user@hostname:/path/to/file1 /path/to/file2\n```\n\n3rd party transfers (start both FDT client and server remotely):\n\n```\nfdt user1@hostname1:/path/to/file1 user2@hostname2:/path/to/file2\n```\n\n##### **3. GSI-SSH mode**\n\nIn this mode the FDT client can use the local GRID security credentials (i.e. proxy certificate) to authenticate to a remote GSI-extended SSH server.\n\n`N.B. In this case, the authentication and authorization is deferred to the GSI-OpenSSH server, which means that any user allowed to connect to this server is also allowed to start FDT client/server.`\n\nThe hosts involved in the transfer have to fulfil the following requirements:\n* the remote hosts need to have installed a GSI-Enabled OpenSSH server;\nThis is usually distributed in the current major grid-middleware software : VDT,gLITE.\nSee http://grid.ncsa.uiuc.edu/ssh/ for more details on how this server can be manually installed and configured.\n* the machine running the FDT client needs to have an Grid-UI interface loaded:\nThe proxy certificate used to authenticate to the remote GSI-SSH server is searched in the following order:\n    1. in the path specified by the X509_USER_PROXY environment variable\n    2. in the default /tmp/x509up_u<uid> location\n\n* there are additional libraries that need to be appended to FDT client CLASSPATH:\n1. Download FDT :\n\n```\n[~/fdt]> wget http://monalisa.cern.ch/FDT/lib/fdt.jar\n```\n\n2. Download gsi-sshterm libs:\n\n```\n[~/fdt]> wget http://www.grid-support.ac.uk/files/gsissh/GSI-SSHTerm-0.79.zip\n[~/fdt]> unzip GSI-SSHTerm-0.79.zip\n```\n\n3. Set the CLASSPATH\n\n```\n[~/fdt]>export GSISSHLIBS=`find GSI-SSHTerm-0.79/lib/ -name \"*.jar\" -printf \"$PWD/%p:\"`\n[~/fdt]>export CLASSPATH=$PWD/fdt.jar:$GSISSHLIBS\n```\n\n4. Set FDT command alias:\n\n```\n[~/fdt]> alias fdt=\"java lia.util.net.copy.FDT\"\n```\n\nThis mode is similar to the previous one in the way the remote FDT instances are started.\nYou have to pass **-gsissh** option to instruct FDT to use Grid credentials.\n\nExample:\nUsing local FDT client to transfer files to/from remote hosts:\n\n```\nfdt -gssish /path/to/file1 user@hostname:/path/to/file2\nfdt -gsissh user@hostname:/path/to/file1 /path/to/file2\n```\n\n3rd party transfers (start both FDT client and server remotely):\n\n```\nfdt -gsissh user1@host1:/path/to/file1 user2@host2:/path/to/file2\n```\n\n##### **4. GSI-enabled FDT server**\n\nThis mode offers a more flexible way to authenticate and authorize users in Grid environments. The control channel between FDT clients and FDT server is secured using Globus GSI API. Mutual authentication is performed between FDT clients and servers.\nTo explicitly set this mode you have to download the Globus JGlobus libraries (see below) , set the CLASSPATH variable accordingly and pass the -gsi parameter when starting the FDT clients and FDT server\n\n**Server side:**\nThe FDT server have to be started using a pair of X509 public/private keys. The search path for these files is:\n* X509_SERVICE_CERT and X509_SERVICE_KEY properties passed to the java virtual machine\n* X509_HOST_CERT and X509_HOST_KEY environment variables\n* /etc/grid-security/hostcert.pem and /etc/grid-security/hostkey.pem files\n\n`Note:\nIt is highly recommended to start the FDT server using an unprivileged account. Usually the host certificates are read protected from unprivileged accounts. In this case you should consider running the FDT server with different service private/public key files.`\n\nThe clients connecting to the server are authenticated using the current environment setup on the server side: CAs certificates, CAs certificate revocation lists directory:\n    **default location:** /etc/grid-security/certificates\n    override with X509_CERT_DIR environment variable\nBy default, the authorization of users is based on grid-mapfile file available in the current Globus installation:\n    **default** /etc/grid-security/grid-mapfile or \n   Override with GRIDMAP java property or environment variable\nOther authorization modules may be plugged-in in the FDT server by specifying : -Dgsi.authz.Authorization=customAuthzPluginClass\n\n**Client side:**\n\nThe machine running the FDT client needs to have an Grid-UI environment loaded:\nThe proxy certificate used to authenticate to the remote GSI-enabled FDT server is searched in the following paths:\nin the path specified by the X509_USER_PROXY environment variable\n\nin the default /tmp/x509up_u<uid> location\n\n###### **4.1. Setup client and server environment**\n\n1. Download Globus GSI (both client and server):\n\n```\n[~/fdt]> wget http://www-unix.globus.org/cog/distribution/1.4/cog-jglobus-1.4-bin.tar.gz\n[~/fdt]> tar -xzvf cog-jglobus-1.4-bin.tar.gz\n```\n\n2. Setup CLASSPATH\n\n```\n[~/fdt]> export JGSILIBS=`find cog-jglobus-1.4/lib/ -name \"*.jar\" -printf \"$PWD/%p:\"`\n[~/fdt]> export CLASSPATH=$PWD/fdt.jar:$JGSILIBS\n```\n\n###### **4.2. Start FDT server**\n\nStart FDT server using /home/fdt/fdtcert.pem and/home/fdt/fdtkey.pem credentials:\n\n```\n[~/fdt]> java -DX509_SERVICE_KEY=/home/fdt/fdtkey.pem -DX509_SERVICE_CERT=/home/fdt/fdtcert.pem lia.util.net.copy.FDT -gsi [server_options]\n```\n\nThe server is using the X509_CERT_DIR environment variable as CAs certificates and CRLs location and default /etc/grid-security/grid-mapfile file to authorize users.\n\n###### **4.3. Start FDT client:**\n\n```\n[~/fdt]> java lia.util.net.copy.FDT -gsi [client_options]\n```\n"
  },
  {
    "path": "docs/doc-system-tuning.md",
    "content": "[[Home](index.md)]  [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[[FDT & DDCopy](doc-fdt-ddcopy.md)]   [[Examples](doc-examples.md)]  [[Security](doc-security.md)]    [[User's Extensions](doc-user-extensions.md)]   [System Tuning]    [[FDT Monitoring](doc-opentsdb.md)]\n\n\n### System Settings\n##### Linux\n\nWe suggest to use newer linux distributions, or if this is not possible, update at least the kernel(2.6.20+). The newer kernels provide adequate TCP settings. We suggest to use the following settings to improve the TCP throughput, especially over long RTT links:\n1. Increase the TCP buffers (newer kernels have this buffers in creased by default). Add the following lines in /etc/sysctl.conf to make the changes permanent accross reboots:\n\n```net.core.rmem_max = 8388608```\n\n```net.core.wmem_max = 8388608```\n\n```net.ipv4.tcp_rmem = 4096 87380 8388608```\n\n```net.ipv4.tcp_wmem = 4096 65536 8388608```\n\n```net.core.netdev_max_backlog = 250000```\n\n```net.ipv4.tcp_no_metrics_save = 1```\n\n```net.ipv4.tcp_moderate_rcvbuf = 1```\n\nAfter adding them just run the following commabd as root:\n    \n```#sysctl -p /etc/sysctl.conf```\n\nThe settings above will set a maximum of 8 MBytes buffers.\nwe suggest to use at least 4Mbytes maximum TCP buffers and a maximum of 16Mbytes should be enough. You should use reasonable values. Don't set very high values for this parameters, and especially don't set the same value for all the fields in net.ipv4.tcp_*. It's also a good practice to have the same value for net.core.r(w)mem_max with the last value in the net.ipv4.tcp_r(w)mem. Do not modify the net.ipv4.tcp_mem parameter. It is computed by the kernel at the system boot.\n\n2. The TCP congestion protocol (if available). To check if it is available for your kernel version:\n\n```$/sbin/sysctl net.ipv4.tcp_congestion_control```\n\nSet it to cubic if kernel version 2.6.20+, and to scalable if older kernels.\n\n```#sysctl -w net.ipv4.tcp_congestion_control=cubic```\n\nTo make this persistent accross reboots add the following line in /etc/sysctl.conf\n\n```net.ipv4.tcp_congestion_control=cubic```\n\nYou may try to experiment various TCP stacks. You can list all of them using:\n\n```$/sbin/sysctl net.ipv4.tcp_available_congestion_control```\n\n3. Increase txqueuelen size your ethernet card\n\n```#ifconfig eth2 txqueuelen 50000```\n\n4. If your network infrastructure supports jumbo frames you may set the MTU size to 9000. Please notice that this setting might broke your AFS installation (newer versions of OpenAFS supports jumbo frames)\n\n```#ifconfig eth2 mtu 9000```\n\nYou may also try to disable the TCP timestamps. On some kernel versions this setting disables the automatic window scalling:\n\n```#sysctl -w net.ipv4.tcp_timestamps=0```\n\nTo make this setting permanent add the following line in /etc/sysctl.conf:\n\n```net.ipv4.tcp_timestamps=0```\n\n##### OpenSolaris\n\nWe obtained good results on OpenSolaris using these setting for the TCP buffers:\n\n```ndd -set /dev/tcp tcp_max_buf 8388608```\n\n```ndd -set /dev/tcp tcp_cwnd_max 4194304```\n\n```ndd -set /dev/tcp tcp_xmit_hiwat 524288```\n\n```ndd -set /dev/tcp tcp_recv_hiwat 524288```\n\nThis page will include other settings or operating systems in the near future.\n\nFor further comments and suggestions please send an email to: support-fdt@monalisa.cern.ch\n"
  },
  {
    "path": "docs/doc-user-extensions.md",
    "content": "[[Home](index.md)]  [Documentation]  [[Performance Tests](perf-disk-to-disk.md)]\n\n[[FDT & DDCopy](doc-fdt-ddcopy.md)]   [[Examples](doc-examples.md)]  [[Security](doc-security.md)]   [User's Extensions]    [[System Tuning](doc-system-tuning.md)]    [[FDT Monitoring](doc-opentsdb.md)]\n\n\n### User's Extensions\nFDT allows to load user defined classes for Pre and Post - Processing of file transfers.\nThis functionality can be used to easily interface FDT with mass storage systems and to implement any additional Access Control List (ACL) to the files transfered by FDT.\n\nIt can also be used for packing, compression or customized integrity check.\n\nThe user can define its own syntax for managing files on different MS systems and the implementation for the Pre/Post Processing interfaces allows the user to define the mechanism to perform local staging or to move the transfered files to a MS system after they are transfered by FDT.\n\nThe two procedures act as filters for the source and destination fields in the FDT syntax.\n\nThe list of files to be transfered, the destination directory and the GSI authentication are passed to the class implementing the PreProcessing interface. If the FDT is used without the GSI authentication the Subject will be a null parameter. Based on the user defined syntax, the implementation can initiate local staging for the files . This can be done in one or multiple threads. It can verify the credentials for the authenticated user to access the files. It can also be used to perform data compression on the files to be transfered.\nIn case the final destination for the files is a MS system on the remote site, the preProcessing implementation should change the destination with a temporary directory on the remote system. The naming scheme for it is used by the PostProcessing implementation to start moving the files to the MS system after the FDT transfer is done. The Post Processing implementation can also be used to verify the user's credentials to write into the MS system to uncompress data, or make an integrity check on the MS system. If the Pre/Post processing classes are used to interface FDT with a MS system, they should modify and act only on files using the user's defined syntax in the name. They should not modify the naming scheme for local files.\n\nThe preProcessing filters must implement **lia.util.net.copy.filters.Preprocessor** interface and the postProcessing filters must implement **lia.util.net.copy.filters.Postprocessor** interface. The functionality of these interfaces may be extended in the future.\n\n\n**Preprocessor.java**\n```\npackage lia.util.net.copy.filters;\n\nimport javax.security.auth.Subject;\n\npublic interface Preprocessor {\npublic void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception;\n}\n```\n\n**Postprocessor.java**\n```\npackage lia.util.net.copy.filters;\n\nimport javax.security.auth.Subject;\n\npublic interface Postprocessor {\npublic void postProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception;\n}\n```\n\n**ProcessorInfo.java**\n```\npackage lia.util.net.copy.filters;\n\npublic class ProcessorInfo {\npublic String[] fileList;\npublic String destinationDir;\n    /**\n     * @since 0.9.25\n     */\n    public InetAddress remoteAddress;\n    /**\n     * @since 0.9.25\n     */\n    public int remotePort;\n    /**\n     * @since 0.9.25\n     */\n    public boolean recursive;\n    /**\n     * Non-null on writer side <b>ONLY</b>.\n     * Gives access to the transfer map of an FDT session.\n     * Key - the final file name (including the destination directory) for a FileSession\n     * Value - the FileSession\n     *\n     * @see FileSession\n     * @since 0.10.0\n     */\n    public Map<string,> fileSessionMap;\n}\n```\n\n### Example\nWe provide a simple example in using this functionality to help users in implementing customized filters.\nIn this example the pre/postProcessing classes are used to compress a list of files before sending and to decompress them at the destination.\n\nTo run the example please download the **FDTZipFilterExample.tar.gz** and follow these steps:\n\n1) Untar the archive and go to FDTZipFilterExample directory. The directory already\ncontains the fdt.jar archive.\n\n2) Go to FDTZipFilterExample directory and use compile.sh script ( javac must be in the $PATH)\nto compile the filters.\n```\n$./compile.sh\n```\n3) To start the FDT server with PostZipFilter already enabled use the startFDTServer.sh script\n```\n$./startFDTServer.sh\n```\n4) To start FDT client and enable PreZipFilter the startFDTClient.sh may be used\n```\n$./startFDTClient.sh -c localhost -d /home/test dataToTransfer\n```\n\nThe **dataToTransfer** file will be first zipped in **dataTransfer.zip** by the **PreZipFilter** and it's name will be changed in the ProcessorInfo and returned to the FDT client. Then the **dataToTransfer.zip** will be transfered to the destination where the **PostZipFilter** will uzip it and delete the zip file.\n>\n"
  },
  {
    "path": "docs/index.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]  [[Performance Tests](perf-disk-to-disk.md)]\n\n### Fast Data Transfer - FDT\n\nFDT is an Application for Efficient Data Transfers which is capable of\nreading and writing at disk speed over wide area networks (with standard TCP).\nIt is written in Java, runs an all major platforms and it is easy to use.\n\nFDT is based on an asynchronous, flexible multithreaded system and is using\nthe capabilities of the Java NIO libraries. Its main features are:\n\n* Streams a dataset (list of files) continuously, using a managed pool of buffers through one or more TCP sockets.\n* Uses independent threads to read and write on each physical device\n* Transfers data in parallel on multiple TCP streams, when necessary\n* Uses appropriate-sized buffers for disk I/O and for the network\n* Restores the files from buffers asynchronously\n* Resumes a file transfer session without loss, when needed\n\nFDT can be used to stream a large set of files across the network, so that\na large dataset composed of thousands of files can be sent or received at\nfull speed, without the network transfer restarting between files.\n\n![Fast Data Transfer Diagram](img/FDT_diagram.png)\n"
  },
  {
    "path": "docs/monitoring-opentsdb.txt",
    "content": "Monitor net test metrics to specified OpenTSDB server:\n#SERVER2\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest\n#SERVER1\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2\n\n\nMonitor net test metrics to specified OpenTSDB server with specific tag:\n#SERVER2\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -fdtTAG <tag>\n#SERVER1\njava -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2 -fdtTAG <tag>\n\n\nMonitor net test metrics to specified OpenTSDB server and using http proxy server:\n#SERVER2\njava -Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port> -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest\n#SERVER1\njava -Dhttp.proxyHost=<host> -Dhttp.proxyPort=<port> -jar fdt.jar -opentsdb <opentsdb-ip:port> -nettest -c $SERVER2"
  },
  {
    "path": "docs/perf-disk-to-disk.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]   [Performance Tests]\n\n[Disk to Disk]   [[Memmory to Memmory](perf-memory-to-memory.md)]   [[SC06](perf-sc06.md)]   [[SC08](perf-sc08.md)]   [[SC09](perf-sc09.md)]\n\n### FDT Disk To Disk I/O Performance over WAN\n \n\n**1. Disk Servers with hardware RAID controllers**\nThis performance test was done using two disk servers between CERN and Caltech (RTT ~ 170 ms). Each system used a 10Gb/s network card (The system at Caltech has a Myricom card and the system at CERN has a Neterion card)\nThe connection between the two systems used the USLHCNET for the transatlantic part and Internet2 in US.\n\nThe disk servers used:\n4U - 2 CPUs Dual Core Intel Woodcrest @ 3.00 GHz, 6 GB RAM, 2 ARECA RAID controllers and 24 SATA HDs.\nThe system at CERN runs Linux (Ubuntu 7.04) kernel 2.6.21.1\nThe system at Caltech run Linux (Centos 4.4) kernel 2.6.18\nFor both systems we used the default TCP congestion control (CUBIC)\nMonALISA was used for all the monitoring.\nThe total transfer rate for data files from CERN to Caltech using the two disk controllers in parallel on both servers is shown in Figure 1.\nTotal network traffic for disk to disk transfer between CERN and Caltech using two RAID controllers per server\n\n![Figure 1. Total network traffic for disk to disk transfer between CERN and Caltech using two RAID controllers per server.](img/figure1.png)\n\nFigure 1. Total network traffic for disk to disk transfer between CERN and Caltech using two RAID controllers per server.\n\nThe total Disk IO on the receiving server (Caltech) is shown in Figure 2.\n\n![Figure 2. Total disk IO for the receiving server (the writer). The mean value is ~ 545 MB/s.](img/figure2.png)\n\nFigure 2. Total disk IO for the receiving server (the writer). The mean value is ~ 545 MB/s.\n\nThe CPU utilization for the receiving server (the writer) is presented in Figure 3. The CPU system is ~ 50% and the used for soft interrupts is ~ 15%.\n\n![Figure 3. The CPU utilization for the receiving server](img/figure3.png)\n\nFigure 3. The CPU utilization for the receiving server\n\n**The mean disk to disk transfer rate between the two servers was 545MB/s, which means 1.96 TB per hour.**\n\nIf we used only one RAID controller in the data transfer on each server the total transfer rate in shown in Figure 4. In this case the mean total throughput is ~ 2.6 Gb/s or 325 MB/s.\n\n![Figure 4. The total network throughput for a Disk to disk transfer between CERN - Caltech, when only \none RAID controller was used on both servers](img/figure4.png)\n\nFigure 4. The total network throughput for a Disk to disk transfer between CERN - Caltech, when only \none RAID controller was used on both servers\n\n##### 2. Simple Servers\n\nThis performance test was done using two 1U servers between CERN and MANLAN (New York) (RTT ~ 93 ms). Each system used a 10Gb/s network card (Netrion ) and we used the USLHCNET.\n\nThe server used:\n\n2 CPUs Dual Core Intel Woodcrest @ 3.00 GHz, 4 GB RAM, 4 x 320 GB SATA HDs.\n\nFDT was used to read and write on parallel on all four SATA HDs on both servers. The total disk IO for the sender server is presented in Figure 5.\n\n![Figure 5. The total disk IO traffic for a data transfer between CERN and MANLAN using in parallel 4 SATA HDs on both servers.](img/figure5.png)\n\nFigure 5. The total disk IO traffic for a data transfer between CERN and MANLAN using in parallel 4 SATA HDs on both servers.\n\nThe mean transfer rate was ~ 210MB/s or 0.75 TB per hour.\n"
  },
  {
    "path": "docs/perf-memory-to-memory.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]   [Performance Tests]\n\n[[Disk to Disk](perf-disk-to-disk.md)]   [Memmory to Memmory]   [[SC06](perf-sc06.md)]   [[SC08](perf-sc08.md)]   [[SC09](perf-sc09.md)]\n\n### FDT Tests for Memory to Memory Transfers\n##### Setup and Topology\n\nThese tests were done on USLHCNET network using the segment between CERN and New York (RTT 93ms).\nThe systems (Cx-NY and Cx-GVA, x=1,2) used for these tests are:\n2 CPUs Dual Core Intel Xenon @ 3.00 GHz, 4 GB RAM, 4 x 320 GB SATA Disks\nConnected with 10Gb/s Myricom cards in the routers at CERN and MANLAN. The topology is presented in Figure 1.\nWe used FDT version 0.5\nWe used 2.6.18 and 2.6.19 Linux kernels. For the TCP congestion control we used Scalable and Cubic. For both we get very similar results.\n\n![Topology of the test environment in using the CERN - MANLAN link](img/figure1-m2m.png)\n\nFigure 1. Topology of the test environment in using the CERN - MANLAN link\n\n##### Transfers in one direction using a pair of servers\nOne pair (C1-NY and C1-GVA) was used to test the maximum throughput we can get from one system.\nWe used 2MB for the TCP buffer size and 35 streams.\nThe throughput in each direction was very stable at ~ 9.2 GB/s (Figure 2). The CPU utilization for the sender and receiver is shown in Figure 3.\n\n![The throughput between C1-NY sender C1-GVA receiver. The TCP buffer size was set to 2MB and we used 35 steams. The RTT is 93ms.](img/figure2-m2m.png)\n\nFigure 2. The throughput between C1-NY sender C1-GVA receiver. The TCP buffer size was set to 2MB and we used 35 steams. The RTT is 93ms.\n\n ![CPU utilization for the sender and receiver](img/figure3-m2m.png)\n \nFigure 3. CPU utilization for the sender and receiver.\n\n##### Transfers in both directions with a pair of servers\n\nWe used one pair (C1-NY and C1-GVA) to concurrently send and receive data on the same 10Gb/s interface. The throughput in each direction was ~ 6 Gb/s (Figure 4).\nPerhaps the limitation is due to the PCI express bus access to the memory. Testing the throughput on a .localhost. is very close to the aggregated traffic obtained in this test.\n\n ![The throughput in both directions between C1-NY C1-GVA. The TCP buffer size was set to 2MB and we used 20 steams for each transfer. The RTT is 93ms](img/figure4-m2m.png)\n \nFigure 4. The throughput in both directions between C1-NY C1-GVA. The TCP buffer size was set to 2MB and we used 20 steams for each transfer. The RTT is 93ms.\n\n##### Transfers in both directions with two pairs of servers\n\nOne pair of servers (C1-NY and C1-GVA) was used to send data from MANLAN to CERN and the other one to send data from CERN to MANLAN. The measured traffic in the MANLAN router is shown in Figure 5. The total throughput in each direction was quite stable. The Traffic from CERN to MANLAN was ~ 9.2Gb/s and the traffic from MANLAN to CERN was ~ 9Gb/s.\n\n ![The throughput in both directions between two pairs of servers. The TCP buffer size was set to 2MB and we used 35 steams for each transfer. The RTT is 93ms](img/figure5-m2m.png)\n \nFigure 5. The throughput in both directions between two pairs of servers. The TCP buffer size was set to 2MB and we used 35 steams for each transfer. The RTT is 93ms\n\n##### Results for Memory to Memory transfers in LAN\n\nThe data transfer between the two systems at CERN (C1-GVA to C2-GVA) or MANLAN (C1-NY to C2-NY) runs very close to the theoretical limit of 10Gb/s (Figure 6 ) and is stable. We used 3 streams with 2MB TCP buffer size.\n\n ![The throughput in LAN between two servers](img/figure6-m2m.png)\n \nFigure 6. The throughput in LAN between two servers.\n"
  },
  {
    "path": "docs/perf-sc06.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]   [Performance Tests]\n\n[[Disk to Disk](perf-disk-to-disk.md)]   [[Memmory to Memmory](perf-memory-to-memory.md)]   [SC06]   [[SC08](perf-sc08.md)]   [[SC09](perf-sc09.md)]\n\n### Fast Data Transfers at SuperComputing 2006\nFDT was used at the Supercomputing 2006, by the Caltech team for the Bandwidth Challenge.\n\nFollowing the rules set for the SC06 Bandwidth Challenge, the team used a single 10-Gbps link that carried data in both directions. FDT provided sustained total throughput of ~17 Gbps for disk to disk transfer using 10 pairs of small servers (each having 4 SATA HD configured in software raid0 and 1Gb/s network interface) in both directions.\n\n![SC06](img/SC06.png)\n"
  },
  {
    "path": "docs/perf-sc08.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]   [Performance Tests]\n\n[[Disk to Disk](perf-disk-to-disk.md)]   [[Memmory to Memmory](perf-memory-to-memory.md)]   [[SC06](perf-sc06.md)]   [SC08]   [[SC09](perf-sc09.md)]\n\n### Fast Data Transfers at SuperComputing 2008\nThe record-setting demonstration was made possible through the use of twelve 10 Gbps links to SC08 provided by SCInet, CENIC, National Lambda Rail, Pacific Wave and Internet2, together with two fully populated Cisco 6509E switches, 10 gigabit Ethernet network interfaces provided by Myricom and Intel, two fiber channel S2A9900 storage platforms provided Data Direct Networks equipped with 8 Gbps host bus adapters from QLogic along with five X4500 and X4540 disk servers from Sun Microsystems. The server equipment consisted of 32 twin motherboards Supermicro systems using dual quad-core Intel Xeon processors.\n\n![FDT @ SC08 Image](img/results08_1.jpg)\n\n### 100G test with Ciena\n\nSecond major milestone was achieved by the HEP team working together with Ciena, who had just completed its first OTU-4 (112 Gbps) standard link carrying a 100 Gbps payload (or 200 Gbps bidirectional) with forward error correction. The Caltech and Ciena teams used an optical fiber cable with ten fiber-pairs linking their neighboring booths, Cienaâ€™s system to multiplex and demultiplex ten 10 Gbps links onto the single OTU-4 wavelength running on an 80 km fiber loop, and some of Caltechâ€™s nodes used in setting the wide area network records together with FDT, to achieve full throughput over the new link. Thanks to FDTâ€™s high throughput capabilities, and the error free links between the booths, the teams were able to achieve a maximum of 199.90 Gbps bi-directionally (memory-to-memory) within minutes of the start of the test, and an average of 191 Gbps during a 12 hour period that logged the transmission of 1.02 Petabytes overnight. \n\n![FDT @ SC08 Image](img/ciena_sc08_1.jpg)\n"
  },
  {
    "path": "docs/perf-sc09.md",
    "content": "[[Home](index.md)]   [[Documentation](doc-fdt-ddcopy.md)]   [Performance Tests]\n\n[[Disk to Disk](perf-disk-to-disk.md)]   [[Memmory to Memmory](perf-memory-to-memory.md)]   [[SC06](perf-sc06.md)]   [[SC08](perf-sc08.md)]   [SC09]\n\n### Fast Data Transfers at SuperComputing 2009\nThe focus of the exhibit was the HEP team's record-breaking demonstration of storage-to-storage data transfer using FDT, over wide area networks from two racks of servers and a network switch-router on the exhibit floor. The high-energy physics team's demonstration \"Moving Towards Terabit/sec Transfers of Scientific Datasets: The LHC Challenge\" achieved a bi-directional peak throughput of 119 gigabits per second (Gbps) and a data flow of more than 110 Gbps that could be sustained indefinitely among clusters of servers on the show floor and at Caltech, Michigan, San Diego, Florida, Fermilab, Brookhaven, CERN, Brazil, Korea, and Estonia. FDT was used at the Supercomputing 2006, by the Caltech team for the Bandwidth Challenge.\n\n![FDT @ SC09 Image](img/results09_2.jpg)\n"
  },
  {
    "path": "lgtm.yml",
    "content": "extraction:\n  java:\n    index:\n      build_command:\n      - ./build-all.sh\n"
  },
  {
    "path": "lib/globus/bouncycastle.LICENSE",
    "content": "Copyright (c) 2000 The Legion Of The Bouncy Castle (http://www.bouncycastle.org) \n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy,\nmodify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions: \n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the\nSoftware. \n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \n"
  },
  {
    "path": "lib/globus/commons-logging.LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "lib/globus/cryptix.LICENSE",
    "content": "Cryptix General Licence\n\nCopyright (C) 1995, 1996, 1997, 1998, 1999, 2000 \nThe Cryptix Foundation Limited. All rights reserved.\n\nRedistribution and use in source and binary forms, with or without \nmodification, are permitted provided that the following conditions \nare met:\n\n1. Redistributions of source code must retain the copyright notice, \n   this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright \n   notice, this list of conditions and the following disclaimer in \n   the documentation and/or other materials provided with the \n   distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED ``AS IS'' \nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, \nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A \nPARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR \nOR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, \nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT \nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF \nUSE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED \nAND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\nIN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF \nTHE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "lib/globus/junit.LICENSE",
    "content": "Common Public License Version 0.5 \n\nTHE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. \n\n\n1. DEFINITIONS \n\n\"Contribution\" means: \n\na) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and \nb) in the case of each subsequent Contributor:\ni) changes to the Program, and\nii) additions to the Program;\nwhere such changes and/or additions to the Program originate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on\nsuch Contributor's behalf. Contributions do not include additions to the Program which: (i) are separate modules of\nsoftware distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works\nof the Program.\n\n\"Contributor\" means any person or entity that distributes the Program. \n\n\n\"Licensed Patents \" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of\nits Contribution alone or when combined with the Program. \n\n\n\"Program\" means the Contributions distributed in accordance with this Agreement. \n\n\n\"Recipient\" means anyone who receives the Program under this Agreement, including all Contributors. \n\n\n2. GRANT OF RIGHTS \n\na) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, distribute\nand sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code\nform.\nb) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the\nContribution of such Contributor, if any, in source code and object code form. This patent license shall apply to the\ncombination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition\nof the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to\nany other combinations which include the Contribution. No hardware per se is licensed hereunder.\nc) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no\nassurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property\nrights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity\nbased on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights\nneeded, if any. For example, if a third party patent license is required to allow Recipient to distribute the Program, it\nis Recipient's responsibility to acquire that license before distributing the Program.\nd) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to\ngrant the copyright license set forth in this Agreement. \n3. REQUIREMENTS \n\nA Contributor may choose to distribute the Program in object code form under its own license agreement, provided that: \n\na) it complies with the terms and conditions of this Agreement; and\nb) its license agreement:\ni) effectively disclaims on behalf of all Contributors all warranties and conditions, express and implied, including\nwarranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness\nfor a particular purpose; \nii) effectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits; \niii) states that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other\nparty; and\niv) states that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software exchange.\nWhen the Program is made available in source code form: \n\na) it must be made available under this Agreement; and \nb) a copy of this Agreement must be included with each copy of the Program. \n\nContributors may not remove or alter any copyright notices contained within the Program. \n\n\n\nEach Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows\nsubsequent Recipients to identify the originator of the Contribution. \n\n\n4. COMMERCIAL DISTRIBUTION \n\nCommercial distributors of software may accept certain responsibilities with respect to end users, business partners and\nthe like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the\nProgram in a commercial product offering should do so in a manner which does not create potential liability for other\nContributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and indemnify every other Contributor (\"Indemnified\nContributor\") against any losses, damages and costs (collectively \"Losses\") arising from claims, lawsuits and other legal\nactions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such\nCommercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations\nin this section do not apply to any claims or Losses relating to any actual or alleged intellectual property\ninfringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in\nwriting of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor\nin, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at\nits own expense. \n\n\nFor example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then\na Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to\nProduct X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this\nsection, the Commercial Contributor would have to defend claims against the other Contributors related to those performance\nclaims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial\nContributor must pay those damages. \n\n\n5. NO WARRANTY \n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining\nthe appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights\nunder this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or interruption of operations. \n\n\n6. DISCLAIMER OF LIABILITY \n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\nHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\nOTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. \n\n\n7. GENERAL \n\nIf any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or\nenforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such\nprovision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. \n\n\nIf Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including\na cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under\nthis Agreement shall terminate as of the date such litigation is filed. In addition, If Recipient institutes patent\nlitigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n(excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. \n\n\nAll Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or\nconditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such\nnoncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of\nthe Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses\ngranted by Recipient relating to the Program shall continue and survive. \n\n\nEveryone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new\nversions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right\nto modify this Agreement. IBM is the initial Agreement Steward. IBM may assign the responsibility to serve as the Agreement\nSteward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The\nProgram (including Contributions) may always be distributed subject to the version of the Agreement under which it was\nreceived. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program\n(including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\nreceives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by\nimplication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. \n\n\nThis Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of\nAmerica. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of\naction arose. Each party waives its rights to a jury trial in any resulting litigation. \n\n\n"
  },
  {
    "path": "lib/globus/log4j.LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 1999-2005 The Apache Software Foundation\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "lib/globus/puretls.LICENSE",
    "content": "  This package is a SSLv3/TLS implementation written by Eric Rescorla\n   <ekr\\@rtfm.com> and licensed by Claymore Systems, Inc.\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions\n   are met:\n   1. Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n   2. Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n   3. Neither the name of Claymore Systems, Inc. nor the name of Eric\n      Rescorla may be used to endorse or promote products derived from this\n      software without specific prior written permission.\n\n   THIS SOFTWARE IS PROVIDED BY CLAYMORE SYSTEMS AND CONTRIBUTORS ``AS IS'' AND\n   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n   ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE\n   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n   SUCH DAMAGE.\n\n"
  },
  {
    "path": "lib/globus/version.txt",
    "content": "PureTLS (custom): 0.9b4\nJUnit version: 3.8.1\n\nTested with:\n - JNDI: 1.2.1\n - LDAP provider: 1.2.3\n - JAAS 1.0_01\n"
  },
  {
    "path": "open_direct.c",
    "content": "/*\n * LD_PRELOAD shim to force files to be opened with the O_DIRECT flag,\n * avoiding cache thrashing and allowing for 0-copy reads/writes.\n *\n * Will compare all open() file names to the prefix FDT_DIRECT_PATH,\n * and if it matches it will add O_DIRECT to the flags passes to\n * the real open64() call.\n *\n * Note that this is a simple string comparison, so things like relative\n * paths or ../s will make things not match.\n * ex:\n *     export FDT_DIRECT_PATH=/home/user/fdt-data\n *     open(\"fdt-data/file1\") <= Will not match, no exact strcmp()\n *     open(\"/home/user/fdt-data/file1\") <= Will set O_DIRECT\n *     open(\"/home/user/fdt-data/dir1/file2\") <= Also matches\n *     open(\"/home/user/fdt-data/../otherfile\") <= Will match, but\n *                  you probably didn't intend it to.\n * Because of this, it is recommended to only use fully qualified paths\n * in directories or files passed into fdt.\n *\n * Licensed under the Apache License 2.0, included with this repo.\n * Earle F. Philhower, III  <earlephilhower@yahoo.com>\n */\n\n/*\n * Compile with:\n *    gcc -shared -fPIC open_direct.c -o open_direct.so -ldl\n * Run FDT:\n *    FDT_DIRECT_PATH=/mnt LD_PRELOAD=./open_direct.so java -jar fdt.jar ..\n */\n\n\n#define _GNU_SOURCE\n#include <dlfcn.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <fcntl.h>\n\n// Match the open64() API\ntypedef int (*open64_type)(const char *path, int f);\n\n// LD_PRELOAD will cause java open64() calls to use this instead of the system\n// version of open64().\nint open64(const char *file, int flags, ...)\n{\n    static const char *directdir = NULL;\n    static int directdirlen = 0;\n    static int skip = 0;\n    static open64_type real_open64 = NULL;\n\n    // First pass through, get the settings and real open64 address\n    if (!directdir && !skip) {\n        real_open64 = (open64_type)dlsym(RTLD_NEXT,\"open64\");\n        directdir = getenv(\"FDT_DIRECT_PATH\");\n        if (!directdir) {\n            skip = 1; // No mask defined, don't do anything...\n        } else {\n            // Cache the length to avoid calling strlen on every open\n            directdirlen = strlen(directdir);\n        }\n    }\n\n    // Now handle the logic of the call.  Rely on C early expression termination\n    if (!skip && !strncmp(directdir, file, directdirlen)) {\n        flags |= O_DIRECT;\n        fprintf(stderr, \"DIRECT opening: '%s'\\n\", file);\n    } else {\n        fprintf(stderr, \"Normal opening: '%s'\\n\", file);\n    }\n    return real_open64(file, flags);\n}\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<groupId>fast-data-transfer</groupId>\n\t<artifactId>fdt</artifactId>\n\t<version>0.27.0-SNAPSHOT</version>\n\t<description>Fast data transfer</description>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<jdk.version>1.8</jdk.version>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>edu.illinois.ncsa</groupId>\n\t\t\t<artifactId>BCGSS</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.bouncycastle</groupId>\n\t\t\t<artifactId>bcprov</artifactId>\n\t\t\t<version>1.50.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>commons-compress</artifactId>\n\t\t\t<version>1.26.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.github.oshi</groupId>\n\t\t\t<artifactId>oshi-core</artifactId>\n\t\t\t<version>6.4.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>net.iharder.dnd</groupId>\n\t\t\t<artifactId>filedrop</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.common</groupId>\n\t\t\t<artifactId>j2ssh-common</artifactId>\n\t\t\t<version>0.2.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.core</groupId>\n\t\t\t<artifactId>j2ssh-core</artifactId>\n\t\t\t<version>0.2.7</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.lirc.socket</groupId>\n\t\t\t<artifactId>jlirc-unix-soc</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>uk.ac.rl.esc.browser</groupId>\n\t\t\t<artifactId>libbrowser</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.logging.log4j</groupId>\n\t\t\t<artifactId>log4j-core</artifactId>\n\t\t\t<version>2.17.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>edu.illinois.ncsa</groupId>\n\t\t\t<artifactId>ncsa-lcrypto</artifactId>\n\t\t\t<version>1.4.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.commons</groupId>\n\t\t\t<artifactId>not-yet-commons-ssl</artifactId>\n\t\t\t<version>0.3.11</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.ext</groupId>\n\t\t\t<artifactId>putty-pk</artifactId>\n\t\t\t<version>1.1.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.tunnel</groupId>\n\t\t\t<artifactId>SecureTunneling</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.shift</groupId>\n\t\t\t<artifactId>ShiFT</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.sshterm</groupId>\n\t\t\t<artifactId>SSHTerm</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.sshtools.sshvnc</groupId>\n\t\t\t<artifactId>SSHVnc</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.jdesktop</groupId>\n\t\t\t<artifactId>swing-layout</artifactId>\n\t\t\t<version>1.0.3</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globusonline</groupId>\n\t\t\t<artifactId>TransferAPIClient</artifactId>\n\t\t\t<version>1.0.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.italiangrid</groupId>\n\t\t\t<artifactId>voms-api-java</artifactId>\n\t\t\t<version>3.0.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus</groupId>\n\t\t\t<artifactId>axisg</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-logging</groupId>\n\t\t\t<artifactId>commons-logging</artifactId>\n\t\t\t<version>1.2</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.json</groupId>\n\t\t\t<artifactId>json</artifactId>\n\t\t\t<version>20231013</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus</groupId>\n\t\t\t<artifactId>gram</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus</groupId>\n\t\t\t<artifactId>gridftp</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus.gsi.gssapi</groupId>\n\t\t\t<artifactId>gss</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus.io</groupId>\n\t\t\t<artifactId>io</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.5.13</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.gson</groupId>\n\t\t\t<artifactId>gson</artifactId>\n\t\t\t<version>2.8.9</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus.jsse</groupId>\n\t\t\t<artifactId>jsse</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>com.google.guava</groupId>\n\t\t\t<artifactId>guava</artifactId>\n\t\t\t<version>r05</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-lang</groupId>\n\t\t\t<artifactId>commons-lang</artifactId>\n\t\t\t<version>2.6</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus.myproxy</groupId>\n\t\t\t<artifactId>myproxy</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.globus</groupId>\n\t\t\t<artifactId>ssl-proxies</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.opentsdb</groupId>\n\t\t\t<artifactId>opentsdb-client</artifactId>\n\t\t\t<version>2.1.0</version>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<sourceDirectory>src</sourceDirectory>\n\t\t<resources>\n\t\t\t<resource>\n\t\t\t\t<directory>src</directory>\n\t\t\t\t<excludes>\n\t\t\t\t\t<exclude>**/*.java</exclude>\n\t\t\t\t</excludes>\n\t\t\t</resource>\n\t\t</resources>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-eclipse-plugin</artifactId>\n\t\t\t\t<version>2.9</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<downloadSources>true</downloadSources>\n\t\t\t\t\t<downloadJavadocs>false</downloadJavadocs>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>2.3.2</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>${jdk.version}</source>\n\t\t\t\t\t<target>${jdk.version}</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>3.1.2</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<!-- DO NOT include log4j.properties file in your Jar -->\n\t\t\t\t\t<excludes>\n\t\t\t\t\t\t<exclude>**/log4j.properties</exclude>\n\t\t\t\t\t</excludes>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<!-- Jar file entry point -->\n\t\t\t\t\t\t\t<mainClass>lia.util.net.copy.FDTMain</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>lia.util.net.copy.FDTMain</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t\t<descriptorRefs>\n\t\t\t\t\t\t<descriptorRef>jar-with-dependencies</descriptorRef>\n\t\t\t\t\t</descriptorRefs>\n\t\t\t\t\t<finalName>${project.artifactId}-${project.version}</finalName>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>make-assembly</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>single</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-antrun-plugin</artifactId>\n\t\t\t\t<version>1.8</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<target>\n\t\t\t\t\t\t\t\t<copy\n\t\t\t\t\t\t\t\t\tfile=\"${project.build.directory}/${project.artifactId}-${project.version}-jar-with-dependencies.jar\"\n\t\t\t\t\t\t\t\t\ttofile=\"${project.build.directory}/fdt.jar\" />\n\t\t\t\t\t\t\t\t<echo file=\"${project.build.directory}/fdt\" append=\"false\">java -jar fdt.jar \"$@\"</echo>\n\t\t\t\t\t\t\t\t<chmod file=\"${project.build.directory}/fdt\" perm=\"ugo+rx\" />\n\t\t\t\t\t\t\t</target>\n\t\t\t\t\t\t\t<filemode>755</filemode>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>run</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n\t\n"
  },
  {
    "path": "src/apmon/ApMon.java",
    "content": "/*\n * ApMon - Application Monitoring Tool\n * Version: 2.2.7\n *\n * Copyright (C) 2006 - 2010 California Institute of Technology\n *\n * Permission is hereby granted, free of charge, to use, copy and modify \n * this software and its documentation (the \"Software\") for any\n * purpose, provided that existing copyright notices are retained in \n * all copies and that this notice is included verbatim in any distributions\n * or substantial portions of the Software. \n * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu).\n * Users of the Software are asked to feed back problems, benefits,\n * and/or suggestions about the software to the MonALISA Development Team\n * (developers@monalisa.cern.ch). Support for this software - fixing of bugs,\n * incorporation of new features - is done on a best effort basis. All bug\n * fixes and enhancements will be made available under the same terms and\n * conditions as the original software,\n \n * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR\n * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\n * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,\n * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS\n * PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO\n * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n * MODIFICATIONS.\n */\n\npackage apmon;\n\nimport apmon.host.cmdExec;\nimport lia.util.net.common.Config;\nimport lia.util.net.common.MonitoringUtils;\n\nimport java.io.*;\nimport java.net.*;\nimport java.util.*;\nimport java.util.logging.*;\n\n/**\n * Data structure used for sending monitoring data to a MonaLisa module.\n * The data is packed in UDP datagrams, in XDR format.\n * A datagram has the following structure:\n * - header which contains the ApMon version and the password for the MonALISA\n * host and has the following syntax: v:<ApMon_version>p:<password>\n * - cluster name (string)\n * - node name (string)\n * - number of parameters (int)\n * - for each parameter: name (string), value type (int), value\n * <BR>\n * There are two ways to send parameters:\n * 1) a single parameter in a packet (with the function sendParameter() which\n * has several overloaded variants\n * 2) multiple parameters in a packet (with the function sendParameters())\n * <BR>\n * ApMon can be configured to send periodically datagrams with monitoring information\n * concerning the current application or the whole system. Some of the monitoring\n * information is only available on Linux systems.\n */\n\npublic class ApMon {\n\n    public static final int MAX_DGRAM_SIZE = 8192;\n    /**\n     * < Maximum UDP datagram size.\n     */\n    public static final int XDR_STRING = 0;\n    /**\n     * < Used to code the string data type\n     */\n    public static final int XDR_INT32 = 2;\n    /**\n     * < Used to code the 4 bytes integer data type\n     */\n    public static final int XDR_REAL32 = 4;\n    /**\n     * < Used to code the 4 bytes real data type\n     */\n    public static final int XDR_REAL64 = 5;\n    /**\n     * < Used to code the 8 bytes real data type\n     */\n    public static final int DEFAULT_PORT = 8884;\n    /**\n     * Time interval (in sec) at which job monitoring datagrams are sent.\n     */\n    public static final int JOB_MONITOR_INTERVAL = 20;\n\n    /** < The default port on which MonALISA listens */\n    /**\n     * Time interval (in sec) at which system monitoring datagams are sent.\n     */\n    public static final int SYS_MONITOR_INTERVAL = 20;\n    /**\n     * Time interval (in sec) at which the configuration files are checked for changes.\n     */\n    public static final int RECHECK_INTERVAL = 600;\n    /**\n     * The maxim number of mesages that will be sent to MonALISA\n     */\n    public static final int MAX_MSG_RATE = 20;\n    /**\n     * The number of time intervals at which ApMon sends general system monitoring information (considering the time\n     * intervals at which ApMon sends system monitoring information).\n     */\n    public static final int GEN_MONITOR_INTERVALS = 100;\n    static final String APMON_VERSION = \"2.2.7\";\n    /**\n     * Constant that indicates this object was initialized from a file.\n     */\n    static final int FILE_INIT = 1;\n\n    /**\n     * Constant that indicates this object was initialized from a list.\n     */\n    static final int LIST_INIT = 2;\n\n    /**\n     * Constant that indicates this object was initialized directly.\n     */\n    static final int DIRECT_INIT = 3;\n    static String osName = System.getProperty(\"os.name\");\n    private static Logger logger = Logger.getLogger(\"apmon\");\n    /**\n     * Java type -> XDR Type mapping\n     **/\n    private static Map mValueTypes = new HashMap();\n\n    static {\n\n        try {\n            LogManager logManager = LogManager.getLogManager();\n\n            //check if LogManager is already defined\n            if (logManager.getProperty(\"handlers\") == null) {\n                try {\n                    FileHandler fh = null;\n                    try {\n                        fh = new FileHandler(\"apmon.log\");\n                        fh.setFormatter(new SimpleFormatter());\n                    } catch (Throwable t) {\n                        t.printStackTrace();\n                    }\n\n                    logger.setUseParentHandlers(false);\n                    logger.addHandler(fh);\n                    logger.setLevel(Level.INFO);\n                } catch (Throwable t) {\n                    System.err.println(\"[ ApMon ] [ static init ] [ logging ] Unable to load default logger props. Cause:\");\n                    t.printStackTrace();\n                }\n            } else {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"[ ApMon ] [ static init ] [ logging ] uses predefined logging properties\");\n                }\n            }\n\n        } catch (Throwable t) {\n            System.err.println(\"[ ApMon ] [ static init ] [ logging ] Unable to check/load default logger props. Cause:\");\n            t.printStackTrace();\n        }\n\n        mValueTypes.put(String.class.getName(), new Integer(XDR_STRING));\n        mValueTypes.put(Short.class.getName(), new Integer(XDR_INT32));\n        mValueTypes.put(Integer.class.getName(), new Integer(XDR_INT32));\n        mValueTypes.put(Float.class.getName(), new Integer(XDR_REAL64));\n        mValueTypes.put(Double.class.getName(), new Integer(XDR_REAL64));\n\n    }\n\n    /**\n     * don't allow a user to send more than MAX_MSG messages per second, in average\n     */\n    protected long prvTime = 0;\n    protected double prvSent = 0;\n    protected double prvDrop = 0;\n    protected long crtTime = 0;\n    protected long crtSent = 0;\n    protected long crtDrop = 0;\n    protected double hWeight = Math.exp(-5.0 / 60.0);\n\n    /** < The size of the data inside the datagram */\n    /**\n     * The initialization source (can be a file or a list).\n     */\n    Object initSource = null;\n    /**\n     * The initialization type (from file / list / directly).\n     */\n    int initType;\n    /**\n     * The configuration file and the URLs are checked for changes at this numer of seconds (if the network connections\n     * are good).\n     */\n    long recheckInterval = RECHECK_INTERVAL;\n    /**\n     * If the configuraion URLs cannot be reloaded, the interval until the next attempt will be increased. This is the\n     * actual value of the interval that is used by ApMon\n     */\n    long crtRecheckInterval = RECHECK_INTERVAL;\n    String clusterName;\n    /**\n     * < The name of the monitored cluster.\n     */\n    String nodeName;\n    /**\n     * < The name of the monitored node.\n     */\n\n    Vector destAddresses;\n    /**\n     * < The IP addresses where the results will be sent.\n     */\n    Vector destPorts;\n    /**\n     * < The ports where the destination hosts listen.\n     */\n    Vector destPasswds;\n    /**\n     * < The Passwdords used for the destination hosts.\n     */\n\n    byte[] buf;\n    /**\n     * < The buffer which holds the message data (encoded in XDR).\n     */\n    int dgramSize;\n    /**\n     * Hashtable which holds theinitialization resources (Files, URLs) that must be periodically checked for changes,\n     * and their latest modification times\n     */\n    Hashtable confResources;\n    ByteArrayOutputStream baos;\n    DatagramSocket dgramSocket;\n    /**\n     * The background thread which performs operations like checking the configuration file/URLs for changes and sending\n     * datagrams with monitoring information.\n     */\n    BkThread bkThread = null;\n    /**\n     * Is true if the background thread was started.\n     */\n    boolean bkThreadStarted = false;\n    /**\n     * Protects the variables that hold the settings for the background thread.\n     */\n    Object mutexBack = new Object();\n    /**\n     * Used for the wait/notify mechanism in the background thread.\n     */\n    Object mutexCond = new Object();\n    /**\n     * Indicates if any of the settings for the background thread was changed.\n     */\n    boolean condChanged = false;\n    /**\n     * These flags indicate changes in the monitoring configuration.\n     */\n    boolean recheckChanged, jobMonChanged, sysMonChanged;\n    /**\n     * If this flag is set to true, when the value of a parameter cannot be read from proc/, ApMon will not attempt to\n     * include that value in the next datagrams.\n     */\n    boolean autoDisableMonitoring = true;\n    /**\n     * If this flag is true, the configuration file / URLs are periodically rechecked for changes.\n     */\n    boolean confCheck = false;\n    /**\n     * If this flag is true, packets with system information taken from /proc are periodically sent to MonALISA\n     */\n    boolean sysMonitoring = false;\n\n    // long appPID;\n    /**\n     * If this flag is true, packets with job information taken from /proc are periodically sent to MonALISA\n     */\n    boolean jobMonitoring = false;\n    /**\n     * If this flag is true, packets with general system information taken from /proc are periodically sent to MonALISA\n     */\n    boolean genMonitoring = false;\n    /**\n     * Job/System monitoring information obtained from /proc is sent at these time intervals\n     */\n    long jobMonitorInterval = JOB_MONITOR_INTERVAL;\n    long sysMonitorInterval = SYS_MONITOR_INTERVAL;\n    int maxMsgRate = MAX_MSG_RATE;\n    /**\n     * General system monitoring information is sent at a time interval equal to genMonitorIntervals *\n     * sysMonitorInterval.\n     */\n    int genMonitorIntervals = GEN_MONITOR_INTERVALS;\n    /**\n     * Hashtables that associate the names of the parameters included in the monitoring datagrams and flags that\n     * indicate whether they are active or not.\n     */\n    long sysMonitorParams, jobMonitorParams, genMonitorParams;\n    /**\n     * The time when the last datagram with job monitoring information was sent (in milliseconds since the Epoch).\n     */\n    long lastJobInfoSend;\n    /**\n     * The time when the last datagram with job monitoring information was sent (in milliseconds since the Epoch).\n     */\n    long lastSysInfoSend;\n    /**\n     * The last value for \"utime\" for the current process that was read from proc/ (only on Linux).\n     */\n    double lastUtime;\n    /**\n     * The last value for \"stime\" for the current process that was read from proc/ (only on Linux).\n     */\n    double lastStime;\n    /**\n     * The name of the host on which ApMon currently runs.\n     */\n    String myHostname = null;\n    /**\n     * The IP address of the host on which ApMon currently runs.\n     */\n    String myIP = null;\n    /**\n     * The number of CPUs on the machine that runs ApMon.\n     */\n    int numCPUs;\n    /**\n     * The names of the network interfaces on this machine.\n     */\n    Vector netInterfaces = new Vector();\n    /**\n     * The IPs of this machine.\n     */\n    Vector allMyIPs = new Vector();\n    /**\n     * the cluster name that will be included in the monitoring datagrams\n     */\n    String sysClusterName = \"ApMon_userSend\";\n    /**\n     * the node name that will be included in the monitoring datagrams\n     */\n    String sysNodeName = null;\n    Vector monJobs = new Vector();\n    Hashtable sender = new Hashtable();\n\n    /**\n     * Initializes an ApMon object from a configuration file.\n     *\n     * @param filename The name of the file which contains the addresses and the ports of the destination hosts (see README\n     *                 for details about the structure of this file).\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    public ApMon(String filename) throws ApMonException, SocketException, IOException {\n\n        initType = FILE_INIT;\n        initMonitoring();\n        initSource = filename;\n        initialize(filename, true);\n        initSenderRef();\n    }\n\n    /**\n     * Initializes an ApMon object from a list with URLs.\n     *\n     * @param destList The list with URLs. the ports of the destination hosts (see README for details about the structure of\n     *                   this file).\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    public ApMon(Vector destList) throws ApMonException, SocketException, IOException {\n        initType = LIST_INIT;\n        initMonitoring();\n        initSource = destList;\n        initialize(destList, true);\n        initSenderRef();\n    }\n\n    /**\n     * Initializes an ApMon data structure, using arrays instead of a file.\n     *\n     * @param destAddresses Array that contains the hostnames or IP addresses of the destination hosts.\n     * @param destPorts     The ports where the MonaLisa modules listen on the destination hosts.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    public ApMon(Vector destAddresses, Vector destPorts) throws ApMonException, SocketException, IOException {\n        this.initType = DIRECT_INIT;\n        arrayInit(destAddresses, destPorts, null);\n        initSenderRef();\n    }\n\n    /**\n     * Initializes an ApMon data structure, using arrays instead of a file.\n     *\n     * @param destAddresses Array that contains the hostnames or IP addresses of the destination hosts.\n     * @param destPorts     The ports where the MonaLisa modules listen on the destination hosts.\n     * @param destPasswds   The passwords for the destination hosts.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    public ApMon(Vector destAddresses, Vector destPorts, Vector destPasswds) throws ApMonException, SocketException, IOException {\n        this.initType = DIRECT_INIT;\n        initMonitoring();\n        arrayInit(destAddresses, destPorts, destPasswds);\n        initSenderRef();\n    }\n\n    /**\n     * Sets the ApMon loglevel. The possible values are: \"FATAL\", \"WARNING\", \"INFO\", \"FINE\", \"DEBUG\".\n     */\n    public static void setLogLevel(String newLevel_s) {\n        int i;\n        String levels_s[] = {\n                \"FATAL\", \"WARNING\", \"INFO\", \"FINE\", \"DEBUG\"\n        };\n        Level levels[] = {\n                Level.SEVERE, Level.WARNING, Level.INFO, Level.FINE, Level.FINEST\n        };\n\n        for (i = 0; i < 5; i++)\n            if (newLevel_s.equals(levels_s[i]))\n                break;\n\n        if (i >= 5) {\n            logger.warning(\"[ setLogLevel() ] Invalid level value: \" + newLevel_s);\n            return;\n        }\n\n        logger.info(\"Setting logging level to \" + newLevel_s);\n        logger.setLevel(levels[i]);\n    }\n\n    // * Supported in Sun JRE >1.5 (returns -1 in prior versions)\n    public static int getPID() {\n        try {\n            final java.lang.management.RuntimeMXBean rt = java.lang.management.ManagementFactory.getRuntimeMXBean();\n            return Integer.parseInt(rt.getName().split(\"@\")[0]);\n        } catch (Throwable t) {\n            return -1;\n        }\n    }\n\n    /**\n     * Add a job pid to monitorized jobs vector\n     */\n    public void addJobToMonitor(int pid, String workDir, String clusterName, String nodeName) {\n        MonitoredJob job = new MonitoredJob(pid, workDir, clusterName, nodeName);\n        if (!monJobs.contains(job))\n            monJobs.add(job);\n        else if (logger.isLoggable(Level.WARNING))\n            logger.warning(\"Job <\" + job + \"> already exsist.\");\n    }\n\n    /**\n     * Remove a pid form monitorized jobs vector\n     */\n    public void removeJobToMonitor(int pid) {\n        int i;\n        for (i = 0; i < monJobs.size(); i++) {\n            MonitoredJob job = (MonitoredJob) monJobs.elementAt(i);\n            if (job.getPid() == pid) {\n                monJobs.remove(job);\n                break;\n            }\n        }\n    }\n\n    /**\n     * This is used to set the cluster and node name for the system-related monitored data.\n     */\n    public void setMonitorClusterNode(String cName, String nName) {\n        if (cName != null)\n            sysClusterName = cName;\n        if (nName != null)\n            sysNodeName = nName;\n    }\n\n    /**\n     * Initializes an ApMon object from a configuration file.\n     *\n     * @param filename  The name of the file which contains the addresses and the ports of the destination hosts (see README\n     *                  for details about the structure of this file).\n     * @param firstTime If it is true, all the initializations will be done (the object is being constructed now). Else, only\n     *                  some structures will be reinitialized.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    void initialize(String filename, boolean firstTime) throws ApMonException, SocketException, IOException {\n        Vector destAddresses = new Vector();\n        Vector destPorts = new Vector();\n        Vector destPasswds = new Vector();\n\n        Hashtable confRes = new Hashtable();\n        try {\n            loadFile(filename, destAddresses, destPorts, destPasswds, confRes);\n        } catch (Exception e) {\n            if (firstTime) {\n                if (e instanceof IOException)\n                    throw (IOException) e;\n                if (e instanceof ApMonException)\n                    throw (ApMonException) e;\n            } else {\n                logger.warning(\"Configuration not reloaded successfully, keeping the previous one\");\n                return;\n            }\n        }\n\n        synchronized (this) {\n            arrayInit(destAddresses, destPorts, destPasswds, firstTime);\n            this.confResources = confRes;\n        }\n    }\n\n    /**\n     * Initializes an ApMon object from a list with URLs.\n     *\n     * @param destList The list with URLs.\n     * @param firstTime  If it is true, all the initializations will be done (the object is being constructed now). Else, only\n     *                   some structures will be reinitialized.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    void initialize(Vector destList, boolean firstTime) throws ApMonException, SocketException, IOException {\n        int i;\n        Vector destAddresses = new Vector();\n        Vector destPorts = new Vector();\n        Vector destPasswds = new Vector();\n        String dest;\n        Hashtable confRes = new Hashtable();\n\n        logger.info(\"Initializing destination addresses & ports:\");\n        try {\n            for (i = 0; i < destList.size(); i++) {\n                dest = (String) destList.get(i);\n                if (dest.startsWith(\"http\")) { // get the list from a remote location\n                    loadURL(dest, destAddresses, destPorts, destPasswds, confRes);\n                } else { // the destination address & port are given directly\n                    addToDestinations(dest, destAddresses, destPorts, destPasswds);\n                }\n            }\n        } catch (Exception e) {\n            if (firstTime) {\n                if (e instanceof IOException)\n                    throw (IOException) e;\n                if (e instanceof ApMonException)\n                    throw (ApMonException) e;\n                if (e instanceof SocketException)\n                    throw (SocketException) e;\n            } else {\n                logger.warning(\"Configuration not reloaded successfully, keeping the previous one\");\n                return;\n            }\n        }\n\n        synchronized (this) {\n            arrayInit(destAddresses, destPorts, destPasswds, firstTime);\n            this.confResources = confRes;\n        }\n    }\n\n    /**\n     * Parses a configuration file which contains addresses, ports and passwords for the destination hosts and puts the\n     * results in the vectors given as parameters.\n     *\n     * @param filename      The name of the configuration file.\n     * @param destAddresses Will contain the destination addresses.\n     * @param destPorts     Will contain the ports from the destination hosts.\n     * @param destPasswds   Will contain the passwords for the destination hosts.\n     * @param confRes       Will contain the configuration resources (file, URLs).\n     * @throws IOException ,\n     *                     ApMonException\n     */\n    void loadFile(String filename, Vector destAddresses, Vector destPorts, Vector destPasswds, Hashtable confRes) throws IOException, ApMonException {\n        String line, tmp;\n        BufferedReader in = new BufferedReader(new FileReader(filename));\n        confRes.put(new File(filename), new Long(System.currentTimeMillis()));\n\n        /** initializations for the destination addresses */\n        logger.info(\"Loading file \" + filename + \"...\");\n\n        /** parse the input file */\n        while ((line = in.readLine()) != null) {\n            tmp = line.trim();\n            // skip empty lines & comment lines\n            if (tmp.length() == 0 || tmp.startsWith(\"#\"))\n                continue;\n            if (tmp.startsWith(\"xApMon_loglevel\")) {\n                StringTokenizer lst = new StringTokenizer(tmp, \" =\");\n                lst.nextToken();\n                setLogLevel(lst.nextToken());\n                continue;\n            }\n            if (tmp.startsWith(\"xApMon_\")) {\n                parseXApMonLine(tmp);\n                continue;\n            }\n\n            addToDestinations(tmp, destAddresses, destPorts, destPasswds);\n        }\n    }\n\n    /**\n     * Parses a web page which contains addresses, ports and passwords for the destination hosts and puts the results in\n     * the vectors given as parameters.\n     *\n     * @param destAddresses Will contain the destination addresses.\n     * @param destPorts     Will contain the ports from the destination hosts.\n     * @param destPasswds   Will contain the passwords for the destination hosts.\n     * @param confRes       Will contain the configuration resources (file, URLs).\n     */\n    void loadURL(String url, Vector destAddresses, Vector destPorts, Vector destPasswds, Hashtable confRes) throws IOException, ApMonException {\n\n        System.setProperty(\"sun.net.client.defaultConnectTimeout\", \"5000\");\n        System.setProperty(\"sun.net.client.defaultReadTimeout\", \"5000\");\n        URL destURL = null;\n        try {\n            destURL = new URL(url);\n        } catch (MalformedURLException e) {\n            throw new ApMonException(e.getMessage());\n        }\n\n        URLConnection urlConn = destURL.openConnection();\n        long lmt = urlConn.getLastModified();\n        confRes.put(new URL(url), new Long(lmt));\n\n        logger.info(\"Loading from URL \" + url + \"...\");\n\n        BufferedReader br = new BufferedReader(new InputStreamReader(destURL.openStream()));\n        String destLine;\n        while ((destLine = br.readLine()) != null) {\n            String tmp2 = destLine.trim();\n            // skip empty lines & comment lines\n            if (tmp2.length() == 0 || tmp2.startsWith(\"#\"))\n                continue;\n            if (tmp2.startsWith(\"xApMon_loglevel\")) {\n                StringTokenizer lst = new StringTokenizer(tmp2, \" =\");\n                lst.nextToken();\n                setLogLevel(lst.nextToken());\n                continue;\n            }\n            if (tmp2.startsWith(\"xApMon_\")) {\n                parseXApMonLine(tmp2);\n                continue;\n\n            }\n            addToDestinations(tmp2, destAddresses, destPorts, destPasswds);\n        }\n        br.close();\n    }\n\n    /**\n     * Parses a line from a (local or remote) configuration file and adds the address and the port to the vectors that\n     * are given as parameters.\n     *\n     * @param line          The line to be parsed.\n     * @param destAddresses Contains destination addresses.\n     * @param destPorts     Contains the ports from the destination hosts.\n     * @param destPasswds   Contains the passwords for the destination hosts.\n     */\n    void addToDestinations(String line, Vector destAddresses, Vector destPorts, Vector destPasswds) {\n        String addr;\n        int port = DEFAULT_PORT;\n        String tokens[] = line.split(\"(\\\\s)+\");\n        String passwd = \"\";\n\n        if (tokens == null)\n            return; // skip blank lines\n\n        line = tokens[0].trim();\n        if (tokens.length > 1)// a password was provided\n            passwd = tokens[1].trim();\n\n        /** the address and the port are separated with \":\" */\n        StringTokenizer st = new StringTokenizer(line, \":\");\n        addr = st.nextToken();\n        try {\n            if (st.hasMoreTokens())\n                port = Integer.parseInt(st.nextToken());\n            else\n                port = DEFAULT_PORT;\n        } catch (NumberFormatException e) {\n            logger.warning(\"Wrong address: \" + line);\n        }\n\n        destAddresses.add(addr);\n        destPorts.add(new Integer(port));\n        if (passwd != null)\n            destPasswds.add(passwd);\n    }\n\n    /**\n     * Internal method used to initialize an ApMon data structure.\n     *\n     * @param destAddresses Array that contains the hostnames or IP addresses of the destination hosts.\n     * @param destPorts     The ports where the MonaLisa modules listen on the destination hosts.\n     * @param destPasswds   The passwords for the destination hosts.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n\n    void arrayInit(Vector destAddresses, Vector destPorts, Vector destPasswds) throws ApMonException, SocketException, IOException {\n        arrayInit(destAddresses, destPorts, destPasswds, true);\n    }\n\n    /**\n     * Internal method used to initialize an ApMon data structure.\n     *\n     * @param destAddresses Array that contains the hostnames or IP addresses of the destination hosts.\n     * @param destPorts     The ports where the MonaLisa modules listen on the destination hosts.\n     * @param destPasswds   The passwords for the destination hosts.\n     * @param firstTime     If it is true, all the initializations will be done (the object is being constructed now). Else, only\n     *                      some of the data structures will be reinitialized.\n     * @throws ApMonException ,\n     *                        SocketException, IOException\n     */\n    void arrayInit(Vector destAddresses, Vector destPorts, Vector destPasswds, boolean firstTime) throws ApMonException, SocketException, IOException {\n\n        Vector tmpAddresses, tmpPorts, tmpPasswds;\n\n        if (destAddresses.size() == 0 || destPorts.size() == 0)\n            throw new ApMonException(\"No destination hosts specified\");\n\n        tmpAddresses = new Vector();\n        tmpPorts = new Vector();\n        tmpPasswds = new Vector();\n\n        /**\n         * put the destination addresses, ports & passwords in some temporary buffers (because we don't want to keep the\n         * monitor while making DNS requests)\n         */\n\n        for (int i = 0; i < destAddresses.size(); i++) {\n            InetAddress inetAddr = InetAddress.getByName((String) destAddresses.get(i));\n            String ipAddr = inetAddr.getHostAddress();\n\n            /**\n             * add the new destination only if it doesn't already exist in this.destAddresses\n             */\n            if (!tmpAddresses.contains(ipAddr)) {\n                tmpAddresses.add(ipAddr);\n                tmpPorts.add(destPorts.get(i));\n                if (destPasswds != null) {\n                    tmpPasswds.add(destPasswds.get(i));\n                }\n                logger.info(\"adding destination: \" + ipAddr + \":\" + destPorts.get(i));\n            }\n        }\n\n        synchronized (this) {\n            this.destPorts = new Vector(tmpPorts);\n            this.destAddresses = new Vector(tmpAddresses);\n            this.destPasswds = new Vector(tmpPasswds);\n        }\n\n        /** these should be done only the first time the function is called */\n        if (firstTime) {\n            cmdExec exec = new cmdExec();\n            myHostname = exec.executeCommand(\"hostname -f\", \"\");\n            exec.stopIt();\n            sysNodeName = myHostname;\n\n            dgramSocket = new DatagramSocket();\n            lastJobInfoSend = System.currentTimeMillis();\n\n            try {\n                lastSysInfoSend = BkThread.getBootTime();\n            } catch (Exception e) {\n                logger.warning(\"Error reading boot time from /proc/stat/.\");\n                lastSysInfoSend = 0;\n            }\n\n            lastUtime = lastStime = 0;\n\n            BkThread.getNetConfig(netInterfaces, allMyIPs);\n            if (allMyIPs.size() > 0)\n                this.myIP = (String) allMyIPs.get(0);\n            else\n                this.myIP = \"unknown\";\n\n            try {\n                baos = new ByteArrayOutputStream();\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                throw new ApMonException(\"Got General Exception while encoding:\" + t);\n            }\n        }\n        /**\n         * start job/system monitoring according to the settings previously read from the configuration file\n         */\n        setJobMonitoring(jobMonitoring, jobMonitorInterval);\n        setSysMonitoring(sysMonitoring, sysMonitorInterval);\n        setGenMonitoring(genMonitoring, genMonitorIntervals);\n        setConfRecheck(confCheck, recheckInterval);\n    }\n\n    /**\n     * For backward compatibility.\n     */\n    public void sendTimedParameters(String clusterName, String nodeName, int nParams, Vector paramNames, Vector valueTypes, Vector paramValues, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendTimedParameters(clusterName, nodeName, nParams, paramNames, paramValues, timestamp);\n    }\n\n    /**\n     * Sends a set of parameters and thier values to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramNames  Vector with the names of the parameters.\n     * @param paramValues Vector with the values of the parameters.\n     * @param timestamp   The user's timestamp\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendTimedParameters(String clusterName, String nodeName, int nParams, Vector paramNames, Vector paramValues, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n\n        int i;\n\n        if (Config.getInstance().getMonitor().equals(Config.OPENTSDB)) {\n            MonitoringUtils monUtils = new MonitoringUtils(Config.getInstance());\n            monUtils.shareMetrics(clusterName, nodeName, paramNames, paramValues);\n        }\n\n        if (!shouldSend())\n            return;\n\n        if (clusterName != null) { // don't keep the cached values for cluster name\n            // and node name\n            this.clusterName = clusterName;\n\n            if (nodeName != null)\n            /** the user provided a name */\n                this.nodeName = new String(nodeName);\n            else {\n                /** set the node name to the node's IP */\n                this.nodeName = this.myHostname;\n            } // else\n        } // if\n\n        updateSEQ_NR();\n        /** try to encode the parameters */\n        encodeParams(nParams, paramNames, paramValues, timestamp);\n\n        synchronized (this) {\n            /** for each destination */\n            for (i = 0; i < destAddresses.size(); i++) {\n                InetAddress destAddr = InetAddress.getByName((String) destAddresses.get(i));\n                int port = ((Integer) destPorts.get(i)).intValue();\n\n                String header = \"v:\" + APMON_VERSION + \"_jp:\";\n                String passwd = \"\";\n                if (destPasswds != null && destPasswds.size() == destAddresses.size()) {\n                    passwd = (String) destPasswds.get(i);\n                }\n                header += passwd;\n\n                byte[] newBuff = null;\n                try {\n                    XDROutputStream xdrOS = new XDROutputStream(baos);\n\n                    xdrOS.writeString(header);\n                    xdrOS.pad();\n                    xdrOS.writeInt(((Integer) sender.get(\"INSTANCE_ID\")).intValue());\n                    xdrOS.pad();\n                    xdrOS.writeInt(((Integer) sender.get(\"SEQ_NR\")).intValue());\n                    xdrOS.pad();\n\n                    xdrOS.flush();\n                    byte[] tmpbuf = baos.toByteArray();\n                    baos.reset();\n\n                    newBuff = new byte[tmpbuf.length + buf.length];\n                    System.arraycopy(tmpbuf, 0, newBuff, 0, tmpbuf.length);\n                    System.arraycopy(buf, 0, newBuff, tmpbuf.length, buf.length);\n\n                } catch (Throwable t) {\n                    logger.warning(\"Cannot add ApMon header....\" + t);\n                    newBuff = buf;\n                }\n\n                if (newBuff == null || newBuff.length == 0) {\n                    logger.warning(\"Cannot send null or 0 length buffer!!\");\n                    continue;\n                }\n\n                dgramSize = newBuff.length;\n                DatagramPacket dp = new DatagramPacket(newBuff, dgramSize, destAddr, port);\n                try {\n                    dgramSocket.send(dp);\n                } catch (IOException e) {\n                    if (logger.isLoggable(Level.WARNING))\n                        logger.warning(\"Error sending parameters to \" + destAddresses.get(i));\n                    dgramSocket.close();\n                    dgramSocket = new DatagramSocket();\n                }\n\n                if (logger.isLoggable(Level.FINE)) {\n                    StringBuffer sbLogMsg = new StringBuffer();\n                    sbLogMsg.append(\" Datagram with size \").append(dgramSize);\n                    sbLogMsg.append(\" sent to \").append(destAddresses.get(i)).append(\", containing parameters:\\n\");\n                    sbLogMsg.append(printParameters(paramNames, paramValues));\n                    logger.log(Level.FINE, sbLogMsg.toString());\n                }\n            }\n        } // synchronized\n    }\n\n    /**\n     * For backward compatibility.\n     */\n    public void sendParameters(String clusterName, String nodeName, int nParams, Vector paramNames, Vector valueTypes, Vector paramValues) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendParameters(clusterName, nodeName, nParams, paramNames, paramValues);\n    }\n\n    /**\n     * Sends a set of parameters and thier values to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramNames  Vector with the names of the parameters.\n     * @param paramValues Vector with the values of the parameters.\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendParameters(String clusterName, String nodeName, int nParams, Vector paramNames, Vector paramValues) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendTimedParameters(clusterName, nodeName, nParams, paramNames, paramValues, -1);\n    }\n\n    /**\n     * For backward compatibility.\n     */\n    public void sendParameter(String clusterName, String nodeName, String paramName, int valueType, Object paramValue) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendParameter(clusterName, nodeName, paramName, paramValue);\n    }\n\n    /**\n     * Sends a parameter and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL, we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendParameter(String clusterName, String nodeName, String paramName, Object paramValue) throws ApMonException, UnknownHostException, SocketException, IOException {\n        Vector paramNames = new Vector();\n        paramNames.add(paramName);\n        Vector paramValues = new Vector();\n        paramValues.add(paramValue);\n\n        sendParameters(clusterName, nodeName, 1, paramNames, paramValues);\n    }\n\n    /**\n     * For backward compatibility.\n     */\n    public void sendTimedParameter(String clusterName, String nodeName, String paramName, int valueType, Object paramValue, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendTimedParameter(clusterName, nodeName, paramName, paramValue, timestamp);\n    }\n\n    /**\n     * Sends a parameter and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL, we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @param timestamp   The user's timestamp\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendTimedParameter(String clusterName, String nodeName, String paramName, Object paramValue, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n        Vector paramNames = new Vector();\n        paramNames.add(paramName);\n        Vector paramValues = new Vector();\n        paramValues.add(paramValue);\n\n        sendTimedParameters(clusterName, nodeName, 1, paramNames, paramValues, timestamp);\n    }\n\n    /**\n     * Sends an integer parameter and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL, we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendParameter(String clusterName, String nodeName, String paramName, int paramValue) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendParameter(clusterName, nodeName, paramName, new Integer(paramValue));\n    }\n\n    /**\n     * Sends an integer parameter and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL, we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @param timestamp   The user's timestamp\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendTimedParameter(String clusterName, String nodeName, String paramName, int paramValue, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n        sendTimedParameter(clusterName, nodeName, paramName, new Integer(paramValue), timestamp);\n    }\n\n    /**\n     * Sends a parameter of type double and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL,we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendParameter(String clusterName, String nodeName, String paramName, double paramValue) throws ApMonException, UnknownHostException, SocketException, IOException {\n\n        sendParameter(clusterName, nodeName, paramName, new Double(paramValue));\n    }\n\n    /**\n     * Sends an integer parameter and its value to the MonALISA module.\n     *\n     * @param clusterName The name of the cluster that is monitored. If it is NULL, we keep the same cluster and node name as in\n     *                    the previous datagram.\n     * @param nodeName    The name of the node from the cluster from which the value was taken.\n     * @param paramName   The name of the parameter.\n     * @param paramValue  The value of the parameter.\n     * @param timestamp   The user's timestamp\n     * @throws ApMonException ,\n     *                        UnknownHostException, SocketException\n     */\n    public void sendTimedParameter(String clusterName, String nodeName, String paramName, double paramValue, int timestamp) throws ApMonException, UnknownHostException, SocketException, IOException {\n\n        sendTimedParameter(clusterName, nodeName, paramName, new Double(paramValue), timestamp);\n    }\n\n    /**\n     * Checks that the size of the stream does not exceed the maximum size of an UDP diagram.\n     */\n    void ensureSize(ByteArrayOutputStream baos) throws ApMonException {\n        if (baos == null)\n            throw new ApMonException(\"Null ByteArrayOutputStream\");\n        if (baos.size() > MAX_DGRAM_SIZE)\n            throw new ApMonException(\"Maximum datagram size exceeded\");\n    }\n\n    /**\n     * Encodes in the XDR format the data from a ApMon structure. Must be called before sending the data over the\n     * newtork.\n     *\n     * @throws ApMonException\n     */\n    void encodeParams(int nParams, Vector paramNames, Vector paramValues, int timestamp) throws ApMonException {\n        int i, valType;\n        try {\n            XDROutputStream xdrOS = new XDROutputStream(baos);\n            /** encode the cluster name, the node name and the number of parameters */\n            ensureSize(baos);\n            xdrOS.writeString(clusterName);\n            xdrOS.pad();\n            xdrOS.writeString(nodeName);\n            xdrOS.pad();\n            xdrOS.writeInt(nParams);\n            xdrOS.pad();\n\n            Object oValue;\n            /** encode the parameters */\n            for (i = 0; i < nParams; i++) {\n\n                /** parameter name */\n                xdrOS.writeString((String) paramNames.get(i));\n                xdrOS.pad();\n                /** parameter value type */\n\n                oValue = paramValues.get(i);\n                valType = ((Integer) mValueTypes.get(oValue.getClass().getName())).intValue();\n                xdrOS.writeInt(valType);\n                xdrOS.pad();\n                /** parameter value */\n                switch (valType) {\n                    case XDR_STRING:\n                        xdrOS.writeString((String) paramValues.get(i));\n                        break;\n                    case XDR_INT32:// INT16 is not supported\n                        int ival = ((Integer) paramValues.get(i)).intValue();\n                        xdrOS.writeInt(ival);\n                        break;\n                    case XDR_REAL64: // REAL32 is not supported\n                        double dval = ((Double) paramValues.get(i)).doubleValue();\n                        xdrOS.writeDouble(dval);\n                        break;\n                    default:\n                        throw new ApMonException(\"Unknown type for XDR encoding\");\n                }\n                xdrOS.pad();\n\n            }// end for()\n\n            /** put the timestamp at the and of XDROutputStream */\n            if (timestamp > 0) {\n                xdrOS.writeInt(timestamp);\n                xdrOS.pad();\n            }\n\n            ensureSize(baos);\n            xdrOS.flush();\n            buf = baos.toByteArray();\n            baos.reset();\n            logger.fine(\"Send buffer length: \" + buf.length + \"B\");\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"\", t);\n            throw new ApMonException(\"Got General Exception while encoding:\" + t);\n        }\n    }\n\n    /**\n     * Returns the value of the confCheck flag. If it is true, the configuration file and/or the URLs are periodically\n     * checked for modifications.\n     */\n    public boolean getConfCheck() {\n        boolean val;\n        synchronized (mutexBack) {\n            val = this.confCheck;\n        }\n        return val;\n    }\n\n    /**\n     * Settings for the periodical configuration rechecking feature.\n     *\n     * @param confCheck If it is true, the configuration rechecking is enabled.\n     * @param interval    The time interval at which the verifications are done. The interval will be automatically increased if\n     *                    ApMon cannot connect to the configuration URLs.\n     */\n    public void setConfRecheck(boolean confCheck, long interval) {\n        int val = -1;\n        if (confCheck)\n            logger.info(\"Enabling configuration reloading (interval \" + interval + \" s)\");\n\n        synchronized (mutexBack) {\n            if (initType == DIRECT_INIT) { // no need to reload onfiguration\n                logger.warning(\"setConfRecheck(): no configuration file/URL to reload\\n\");\n            } else {\n                this.confCheck = confCheck;\n                if (confCheck) {\n                    if (interval > 0) {\n                        this.recheckInterval = interval;\n                        this.crtRecheckInterval = interval;\n                    } else {\n                        this.recheckInterval = RECHECK_INTERVAL;\n                        this.crtRecheckInterval = RECHECK_INTERVAL;\n                    }\n                    val = 1;\n                } else {\n                    if (jobMonitoring == false && sysMonitoring == false)\n                        val = 0;\n                }\n            }\n        } // synchronized\n\n        if (val == 1) {\n            setBackgroundThread(true);\n            return;\n        }\n        if (val == 0) {\n            setBackgroundThread(false);\n            return;\n        }\n    }\n\n    /**\n     * Returns the requested value of the time interval (in seconds) between two recheck operations for the\n     * configuration files.\n     */\n    public long getRecheckInterval() {\n        long val;\n        synchronized (mutexBack) {\n            val = this.recheckInterval;\n        }\n        return val;\n    }\n\n    /**\n     * Sets the value of the time interval (in seconds) between two recheck operations for the configuration file/URLs.\n     * If the value is negative, the configuration rechecking is\n     * turned off.\n     */\n    public void setRecheckInterval(long val) {\n        if (val > 0)\n            setConfRecheck(true, val);\n        else\n            setConfRecheck(false, val);\n    }\n\n    /**\n     * Returns the actual value of the time interval (in seconds) between two recheck operations for the configuration\n     * file/URLs.\n     */\n    long getCrtRecheckInterval() {\n        long val;\n        synchronized (mutexBack) {\n            val = this.crtRecheckInterval;\n        }\n        return val;\n    }\n\n    void setCrtRecheckInterval(long val) {\n        synchronized (mutexBack) {\n            crtRecheckInterval = val;\n        }\n    }\n\n    /**\n     * Settings for the job monitoring feature.\n     *\n     * @param jobMonitoring If it is true, the job monitoring is enabled.\n     * @param interval      The time interval at which the job monitoring datagrams are sent.\n     */\n    public void setJobMonitoring(boolean jobMonitoring, long interval) {\n        int val = -1;\n        if (jobMonitoring)\n            logger.info(\"Enabling job monitoring, time interval \" + interval + \" s\");\n        else\n            logger.info(\"Disabling job monitoring...\");\n\n        synchronized (mutexBack) {\n            this.jobMonitoring = jobMonitoring;\n            this.jobMonChanged = true;\n            if (jobMonitoring == true) {\n                if (interval > 0)\n                    this.jobMonitorInterval = interval;\n                else\n                    this.jobMonitorInterval = JOB_MONITOR_INTERVAL;\n                val = 1;\n            } else {\n                // disable the background thread if it is not needed anymore\n                if (this.sysMonitoring == false && this.confCheck == false)\n                    val = 0;\n            }\n        }\n        if (val == 1) {\n            setBackgroundThread(true);\n            return;\n        }\n        if (val == 0) {\n            setBackgroundThread(false);\n            return;\n        }\n    }\n\n    /**\n     * Returns the value of the interval at which the job monitoring datagrams are sent.\n     */\n    public long getJobMonitorInterval() {\n        long val;\n        synchronized (mutexBack) {\n            val = this.jobMonitorInterval;\n        }\n        return val;\n    }\n\n    /**\n     * Returns true if the job monitoring is enabled and false otherwise.\n     */\n    public boolean getJobMonitoring() {\n        boolean val;\n        synchronized (mutexBack) {\n            val = this.jobMonitoring;\n        }\n        return val;\n    }\n\n    /**\n     * Settings for the system monitoring feature.\n     *\n     * @param sysMonitoring If it is true, the system monitoring is enabled.\n     * @param interval      The time interval at which the system monitoring datagrams are sent.\n     */\n    public void setSysMonitoring(boolean sysMonitoring, long interval) {\n        int val = -1;\n        if (sysMonitoring)\n            logger.info(\"Enabling system monitoring, time interval \" + interval + \" s\");\n        else\n            logger.info(\"Disabling system monitoring...\");\n\n        synchronized (mutexBack) {\n            this.sysMonitoring = sysMonitoring;\n            this.sysMonChanged = true;\n            if (sysMonitoring == true) {\n                if (interval > 0)\n                    this.sysMonitorInterval = interval;\n                else\n                    this.sysMonitorInterval = SYS_MONITOR_INTERVAL;\n                val = 1;\n            } else {\n                // disable the background thread if it is not needed anymore\n                if (this.jobMonitoring == false && this.confCheck == false)\n                    val = 0;\n            }\n        }\n\n        if (val == 1) {\n            setBackgroundThread(true);\n            return;\n        }\n\n        if (val == 0) {\n            setBackgroundThread(false);\n            return;\n        }\n    }\n\n    /**\n     * Returns the value of the interval at which the system monitoring datagrams are sent.\n     */\n    public long getSysMonitorInterval() {\n        long val;\n        synchronized (mutexBack) {\n            val = this.sysMonitorInterval;\n        }\n\n        return val;\n    }\n\n    /**\n     * Returns true if the job monitoring is enabled and false otherwise.\n     */\n    public boolean getSysMonitoring() {\n        boolean val;\n        synchronized (mutexBack) {\n            val = this.sysMonitoring;\n        }\n        return val;\n    }\n\n    /**\n     * Settings for the general system monitoring feature.\n     *\n     * @param genMonitoring If it is true, the general system monitoring is enabled.\n     * @param nIntervals      The number of time intervals at which the general system monitoring datagrams are sent (a\n     *                      \"time interval\" is the time interval between two subsequent system\n     *                      monitoring datagrams).\n     */\n    public void setGenMonitoring(boolean genMonitoring, int nIntervals) {\n\n        logger.info(\"Setting general information monitoring to \" + genMonitoring);\n\n        synchronized (mutexBack) {\n            this.genMonitoring = genMonitoring;\n            this.recheckChanged = true;\n            if (genMonitoring == true) {\n                if (nIntervals > 0)\n                    this.genMonitorIntervals = nIntervals;\n                else\n                    this.genMonitorIntervals = GEN_MONITOR_INTERVALS;\n            }\n        }\n\n        /** automatically set system monitoring to true if necessary */\n        if (genMonitoring && this.sysMonitoring == false) {\n            setSysMonitoring(true, SYS_MONITOR_INTERVAL);\n        }\n    }\n\n    /**\n     * Returns true if the general system monitoring is enabled and false otherwise.\n     */\n    public boolean getGenMonitoring() {\n        boolean val;\n        synchronized (mutexBack) {\n            val = this.genMonitoring;\n        }\n        return val;\n    }\n\n    public Double getSystemParameter(String paramName) {\n        if (bkThread == null) {\n            logger.info(\"The background thread is not started - returning null\");\n            return null;\n        }\n\n        if (bkThread.monitor == null) {\n            logger.info(\"No HostPropertiesMonitor defined - returning null\");\n            return null;\n        }\n\n        HashMap hms = bkThread.monitor.getHashParams();\n        if (hms == null) {\n            logger.info(\"No parameters map defined - returning null\");\n            return null;\n        }\n\n        Long paramId = (Long) ApMonMonitoringConstants.HT_SYS_NAMES_TO_CONSTANTS.get(\"sys_\" + paramName);\n\n        if (paramId == null) {\n            logger.info(\"The parameter \" + paramName + \" does not exist.\");\n            return null;\n        }\n\n        String paramValue = (String) hms.get(paramId);\n        double dVal = -1;\n        try {\n            dVal = Double.parseDouble(paramValue);\n        } catch (Exception e) {\n            logger.info(\"Could not obtain parameter value from the map: \" + paramName);\n            return null;\n        }\n        return new Double(dVal);\n    }\n\n    /**\n     * Enables or disables the background thread.\n     */\n    void setBackgroundThread(boolean val) {\n        boolean stoppedThread = false;\n\n        synchronized (mutexCond) {\n            condChanged = false;\n            if (val == true)\n                if (!bkThreadStarted) {\n                    bkThreadStarted = true;\n                    bkThread = new BkThread(this);\n                    // bkThread.setDaemon(true);\n                    bkThread.start();\n                } else {\n                    condChanged = true;\n                    mutexCond.notify();\n                }\n\n            if (val == false && bkThreadStarted) {\n                bkThread.stopIt();\n                condChanged = true;\n                mutexCond.notify();\n                stoppedThread = true;\n                logger.info(\"[Stopping the thread for configuration reloading...]\\n\");\n            }\n        }\n        if (stoppedThread) {\n            try {\n                // debugging stuff...\n                /*\n                 * System.out.println(\"### active count: \" + bkThread.activeCount()); Thread[] tarray = new Thread[500];\n                 * bkThread.enumerate(tarray); for (int tz = 0; tz <\n                 * tarray.length; tz++) { if (tarray[tz] != null) System.out.println(\"### \" + tarray[tz]); }\n                 */\n                bkThread.join();\n            } catch (Exception e) {\n            }\n            bkThreadStarted = false;\n        }\n    }\n\n    /**\n     * This sets the maxim number of messages that are send to MonALISA in one second. Default, this number is 50.\n     */\n    public void setMaxMsgRate(int maxRate) {\n        this.maxMsgRate = maxRate;\n    }\n\n    /**\n     * Must be called when the ApMon object is no longer in use. Closes the UDP socket used for sending the parameters\n     * and sends a last job monitoring datagram to register the time\n     * when the application was finished.\n     */\n    public void stopIt() {\n\n        if (bkThreadStarted) {\n            if (jobMonitoring) {\n                logger.info(\"Sending last job monitoring packet...\");\n                /**\n                 * send a datagram with job monitoring information which covers the last time interval\n                 */\n                bkThread.sendJobInfo();\n            }\n        }\n        dgramSocket.close();\n        if (bkThread != null)\n            bkThread.monitor.stopIt();\n        setBackgroundThread(false);\n    }\n\n    /**\n     * Initializes the data structures used to configure the monitoring part of ApMon.\n     */\n    void initMonitoring() {\n        autoDisableMonitoring = true;\n        sysMonitoring = false;\n        jobMonitoring = false;\n        genMonitoring = false;\n        confCheck = false;\n\n        recheckInterval = RECHECK_INTERVAL;\n        crtRecheckInterval = RECHECK_INTERVAL;\n        jobMonitorInterval = JOB_MONITOR_INTERVAL;\n        sysMonitorInterval = SYS_MONITOR_INTERVAL;\n\n        sysMonitorParams = 0L;\n\n        /** CPU usage percent */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_CPU_USAGE;\n        /** average system load over the last minute */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_LOAD1;\n        /** average system load over the 5 min */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_LOAD5;\n        /** average system load over the 15 min */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_LOAD15;\n        /** percent of the time spent by the CPU in user mode */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_CPU_USR;\n        /** percent of the time spent by the CPU in system mode */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_CPU_SYS;\n        /** percent of the CPU idle time */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_CPU_IDLE;\n        /** percent of the time spent by the CPU in nice mode */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_CPU_NICE;\n        /** amount of free memory, in MB */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_MEM_FREE;\n        /** used system memory in percent */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_MEM_USAGE;\n        /** amount of currently used memory, in MB */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_MEM_USED;\n        /** amount of currently used swap, in MB */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_PAGES_IN;\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_PAGES_OUT;\n        /** network (input) transfer in KBps */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_NET_IN;\n        /** network (output) transfer in KBps */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_NET_OUT;\n        /** number of processes in thesystem */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_PROCESSES;\n        /** number of opened sockets for each proto => sockets_tcp/udp/unix */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_NET_SOCKETS;\n        /** number of tcp sockets in each state => sockets_tcp_LISTEN, ... */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_NET_TCP_DETAILS;\n        /** swap used, in MB */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_SWAP_USED;\n        /** swap free, in MB */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_SWAP_FREE;\n        /** swap usage in percent */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_SWAP_USAGE;\n        /** number of network errors */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_NET_ERRS;\n        /** in days */\n        sysMonitorParams |= ApMonMonitoringConstants.SYS_UPTIME;\n\n        genMonitorParams = 0L;\n\n        genMonitorParams |= ApMonMonitoringConstants.GEN_HOSTNAME;\n        genMonitorParams |= ApMonMonitoringConstants.GEN_IP;\n\n        if (osName.indexOf(\"Linux\") >= 0) {\n            genMonitorParams |= ApMonMonitoringConstants.GEN_CPU_MHZ;\n            /** number of the CPUs in the system */\n            genMonitorParams |= ApMonMonitoringConstants.GEN_NO_CPUS;\n            /** total amount of system memory in MB */\n            genMonitorParams |= ApMonMonitoringConstants.GEN_TOTAL_MEM;\n            /** total amount of swap in MB */\n            genMonitorParams |= ApMonMonitoringConstants.GEN_TOTAL_SWAP;\n\n            genMonitorParams |= ApMonMonitoringConstants.GEN_CPU_VENDOR_ID;\n\n            genMonitorParams |= ApMonMonitoringConstants.GEN_CPU_FAMILY;\n\n            genMonitorParams |= ApMonMonitoringConstants.GEN_CPU_MODEL;\n\n            genMonitorParams |= ApMonMonitoringConstants.GEN_CPU_MODEL_NAME;\n\n            genMonitorParams |= ApMonMonitoringConstants.GEN_BOGOMIPS;\n        }\n\n        jobMonitorParams = 0L;\n\n        /** elapsed time from the start of this job in seconds */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_RUN_TIME;\n        /** processor time spent running this job in seconds */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_CPU_TIME;\n        /** current percent of the processor used for this job, as reported by ps */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_CPU_USAGE;\n        /** percent of the memory occupied by the job, as reported by ps */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_MEM_USAGE;\n        /** size in MB of the working directory of the job */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_WORKDIR_SIZE;\n        /** size in MB of the total size of the disk partition containing the working directory */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_DISK_TOTAL;\n        /** size in MB of the used disk partition containing the working directory */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_DISK_USED;\n        /** size in MB of the free disk partition containing the working directory */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_DISK_FREE;\n        /** percent of the used disk partition containing the working directory */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_DISK_USAGE;\n        /** size in KB of the virtual memory occupied by the job, as reported by ps */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_VIRTUALMEM;\n        /** size in KB of the resident image size of the job, as reported by ps */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_RSS;\n        /** opended files by job */\n        jobMonitorParams |= ApMonMonitoringConstants.JOB_OPEN_FILES;\n    }\n\n    /*******************************************************************************************************************************************************************************\n     * Parses a \"xApMon\" line from the configuration file and changes the ApMon settings according to the line.\n     */\n    protected void parseXApMonLine(String line) {\n        boolean flag = false, found;\n\n        /** the line has the syntax \"xApMon_parameter = value\" */\n        String tmp = line.replaceFirst(\"xApMon_\", \"\");\n        StringTokenizer st = new StringTokenizer(tmp, \" \\t=\");\n        String param = st.nextToken();\n        String value = st.nextToken();\n\n        /** for boolean values */\n        if (value.equals(\"on\"))\n            flag = true;\n        if (value.equals(\"off\"))\n            flag = false;\n\n        synchronized (mutexBack) {\n            found = false;\n            if (param.equals(\"job_monitoring\")) {\n                this.jobMonitoring = flag;\n                found = true;\n            }\n            if (param.equals(\"sys_monitoring\")) {\n                this.sysMonitoring = flag;\n                found = true;\n            }\n            if (param.equals(\"job_interval\")) {\n                this.jobMonitorInterval = Long.parseLong(value);\n                found = true;\n            }\n            if (param.equals(\"sys_interval\")) {\n                this.sysMonitorInterval = Long.parseLong(value);\n                found = true;\n            }\n            if (param.equals(\"general_info\")) {\n                this.genMonitoring = flag;\n                found = true;\n            }\n            if (param.equals(\"conf_recheck\")) {\n                this.confCheck = flag;\n                found = true;\n            }\n            if (param.equals(\"recheck_interval\")) {\n                this.recheckInterval = this.crtRecheckInterval = Long.parseLong(value);\n                found = true;\n            }\n            if (param.equals(\"maxMsgRate\")) {\n                this.maxMsgRate = Integer.parseInt(value);\n                found = true;\n            }\n            if (param.equals(\"auto_disable\")) {\n                this.autoDisableMonitoring = flag;\n                found = true;\n            }\n        }\n\n        if (found)\n            return;\n\n        /***************************************************************************************************************************************************************************\n         * mutexBack protects the variables which hold settings for the backgrund thread (for sending monitoring\n         * information and for rechecking the configuration file/URLS)\n         */\n        synchronized (mutexBack) {\n            found = false;\n            Long val = null;\n\n            if (param.startsWith(\"sys\")) {\n                val = ApMonMonitoringConstants.getSysIdx(param);\n                long lval = val.longValue();\n                if (flag) {\n                    sysMonitorParams |= lval;\n                } else {\n                    sysMonitorParams &= ~lval;\n                }\n            } else if (param.startsWith(\"job\")) {\n                val = ApMonMonitoringConstants.getJobIdx(param);\n                long lval = val.longValue();\n                if (flag) {\n                    jobMonitorParams |= lval;\n                } else {\n                    jobMonitorParams &= ~lval;\n                }\n            }\n\n            if (val == null) {\n                logger.warning(\"Invalid parameter name in the configuration file: \" + param);\n            } else {\n                found = true;\n            }\n\n        }\n\n        if (!found)\n            logger.warning(\"Invalid parameter name in the configuration file: \" + param);\n    }\n\n    void setSenderRef(Hashtable s) {\n        sender = s;\n    }\n\n    void initSenderRef() {\n        sender.put(\"SEQ_NR\", new Integer(0));\n        sender.put(\"INSTANCE_ID\", new Integer((new Random()).nextInt(0x7FFFFFFF)));\n    }\n\n    void updateSEQ_NR() {\n        Integer seq_nr = (Integer) sender.get(\"SEQ_NR\");\n        sender.put(\"SEQ_NR\", new Integer((seq_nr.intValue() + 1) % 2000000000));\n    }\n\n    /**\n     * Displays the names, values and types of a set of parameters.\n     *\n     * @param paramNames  Vector with the parameters' names.\n     * @param paramValues Vector with the values of the parameters.\n     */\n    String printParameters(Vector paramNames, Vector paramValues) {\n        int i;\n        StringBuffer res = new StringBuffer();\n        for (i = 0; i < paramNames.size(); i++) {\n            String name = (String) paramNames.get(i);\n            res.append(name).append(paramValues.get(i));\n        }\n        return res.toString();\n    }\n\n    /**\n     * Decide if the current datagram should be sent. This decision is based on the number of messages previously sent.\n     */\n    public boolean shouldSend() {\n\n        long now = (new Date()).getTime() / 1000;\n        boolean doSend;\n\n        if (now != crtTime) {\n            /** new time, update previous counters; */\n            prvSent = hWeight * prvSent + (1.0 - hWeight) * crtSent / (now - crtTime);\n            prvTime = crtTime;\n            logger.log(Level.FINE, \"previously sent: \" + crtSent + \" dropped: \" + crtDrop);\n            /** reset current counter */\n            crtTime = now;\n            crtSent = 0;\n            crtDrop = 0;\n        }\n\n        /** compute the history */\n        int valSent = (int) (prvSent * hWeight + crtSent * (1.0 - hWeight));\n\n        doSend = true;\n        /** when we should start dropping messages */\n        int level = this.maxMsgRate - this.maxMsgRate / 10;\n\n        if (valSent > (this.maxMsgRate - level))\n            doSend = (new Random()).nextInt(this.maxMsgRate / 10) < (this.maxMsgRate - valSent);\n\n        /** counting sent and dropped messages */\n        if (doSend) {\n            crtSent++;\n        } else {\n            crtDrop++;\n        }\n\n        return doSend;\n    }\n\n    public String getMyHostname() {\n        return myHostname;\n    }\n\n}\n"
  },
  {
    "path": "src/apmon/ApMonException.java",
    "content": "/*\n * ApMon - Application Monitoring Tool\n * Version: 2.2.7\n *\n * Copyright (C) 2006 - 2010 California Institute of Technology\n *\n * Permission is hereby granted, free of charge, to use, copy and modify \n * this software and its documentation (the \"Software\") for any\n * purpose, provided that existing copyright notices are retained in \n * all copies and that this notice is included verbatim in any distributions\n * or substantial portions of the Software. \n * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu).\n * Users of the Software are asked to feed back problems, benefits,\n * and/or suggestions about the software to the MonALISA Development Team\n * (developers@monalisa.cern.ch). Support for this software - fixing of bugs,\n * incorporation of new features - is done on a best effort basis. All bug\n * fixes and enhancements will be made available under the same terms and\n * conditions as the original software,\n \n * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR\n * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\n * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,\n * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS\n * PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO\n * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n * MODIFICATIONS.\n */\npackage apmon;\n\n/***\n * Internal exception class.\n */\npublic class ApMonException extends Exception {\n\n    static final long serialVersionUID = 979899100;\n\n    public ApMonException(String s) {\n        super(s);\n    }\n}\n"
  },
  {
    "path": "src/apmon/ApMonMonitoringConstants.java",
    "content": "/*\n * ApMon - Application Monitoring Tool\n * Version: 2.2.7\n *\n * Copyright (C) 2006 - 2010 California Institute of Technology\n *\n * Permission is hereby granted, free of charge, to use, copy and modify \n * this software and its documentation (the \"Software\") for any\n * purpose, provided that existing copyright notices are retained in \n * all copies and that this notice is included verbatim in any distributions\n * or substantial portions of the Software. \n * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu).\n * Users of the Software are asked to feed back problems, benefits,\n * and/or suggestions about the software to the MonALISA Development Team\n * (developers@monalisa.cern.ch). Support for this software - fixing of bugs,\n * incorporation of new features - is done on a best effort basis. All bug\n * fixes and enhancements will be made available under the same terms and\n * conditions as the original software,\n \n * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR\n * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\n * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,\n * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS\n * PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO\n * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n * MODIFICATIONS.\n */\n\npackage apmon;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\n\n\npublic final class ApMonMonitoringConstants {\n\n    //SYS_* Specific\n    public static final long SYS_LOAD1 = 0x1L;\n    public static final Long LSYS_LOAD1 = new Long(SYS_LOAD1);\n    public static final long SYS_LOAD5 = 0x2L;\n    public static final Long LSYS_LOAD5 = new Long(SYS_LOAD5);\n    public static final long SYS_LOAD15 = 0x4L;\n    public static final Long LSYS_LOAD15 = new Long(SYS_LOAD15);\n\n    public static final long SYS_CPU_USR = 0x8L;\n    public static final Long LSYS_CPU_USR = new Long(SYS_CPU_USR);\n    public static final long SYS_CPU_SYS = 0x10L;\n    public static final Long LSYS_CPU_SYS = new Long(SYS_CPU_SYS);\n    public static final long SYS_CPU_IDLE = 0x20L;\n    public static final Long LSYS_CPU_IDLE = new Long(SYS_CPU_IDLE);\n    public static final long SYS_CPU_NICE = 0x40L;\n    public static final Long LSYS_CPU_NICE = new Long(SYS_CPU_NICE);\n    public static final long SYS_CPU_USAGE = 0x80L;\n    public static final Long LSYS_CPU_USAGE = new Long(SYS_CPU_USAGE);\n\n    public static final long SYS_MEM_FREE = 0x100L;\n    public static final Long LSYS_MEM_FREE = new Long(SYS_MEM_FREE);\n    public static final long SYS_MEM_USED = 0x200L;\n    public static final Long LSYS_MEM_USED = new Long(SYS_MEM_USED);\n    public static final long SYS_MEM_USAGE = 0x400L;\n    public static final Long LSYS_MEM_USAGE = new Long(SYS_MEM_USAGE);\n\n    public static final long SYS_PAGES_IN = 0x800L;\n    public static final Long LSYS_PAGES_IN = new Long(SYS_PAGES_IN);\n    public static final long SYS_PAGES_OUT = 0x1000L;\n    public static final Long LSYS_PAGES_OUT = new Long(SYS_PAGES_OUT);\n\n    public static final long SYS_NET_IN = 0x2000L;\n    public static final Long LSYS_NET_IN = new Long(SYS_NET_IN);\n    public static final long SYS_NET_OUT = 0x4000L;\n    public static final Long LSYS_NET_OUT = new Long(SYS_NET_OUT);\n    public static final long SYS_NET_ERRS = 0x8000L;\n    public static final Long LSYS_NET_ERRS = new Long(SYS_NET_ERRS);\n\n    public static final long SYS_SWAP_FREE = 0x10000L;\n    public static final Long LSYS_SWAP_FREE = new Long(SYS_SWAP_FREE);\n    public static final long SYS_SWAP_USED = 0x20000L;\n    public static final Long LSYS_SWAP_USED = new Long(SYS_SWAP_USED);\n    public static final long SYS_SWAP_USAGE = 0x40000L;\n    public static final Long LSYS_SWAP_USAGE = new Long(SYS_SWAP_USAGE);\n\n    public static final long SYS_PROCESSES = 0x80000L;\n    public static final Long LSYS_PROCESSES = new Long(SYS_PROCESSES);\n\n    public static final long SYS_NET_SOCKETS = 0x100000L;\n    public static final Long LSYS_NET_SOCKETS = new Long(SYS_NET_SOCKETS);\n\n    public static final long SYS_NET_TCP_DETAILS = 0x200000L;\n    public static final Long LSYS_NET_TCP_DETAILS = new Long(SYS_NET_TCP_DETAILS);\n\n    public static final long SYS_UPTIME = 0x400000L;\n    public static final Long LSYS_UPTIME = new Long(SYS_UPTIME);\n    //GENERIC_*\n    public static final long GEN_HOSTNAME = 0x1L;\n    public static final Long LGEN_HOSTNAME = new Long(GEN_HOSTNAME);\n    public static final long GEN_IP = 0x2L;\n    public static final Long LGEN_IP = new Long(GEN_IP);\n    public static final long GEN_CPU_MHZ = 0x4L;\n    public static final Long LGEN_CPU_MHZ = new Long(GEN_CPU_MHZ);\n    public static final long GEN_NO_CPUS = 0x8L;\n    public static final Long LGEN_NO_CPUS = new Long(GEN_NO_CPUS);\n    public static final long GEN_TOTAL_MEM = 0x10L;\n    public static final Long LGEN_TOTAL_MEM = new Long(GEN_TOTAL_MEM);\n    public static final long GEN_TOTAL_SWAP = 0x20L;\n    public static final Long LGEN_TOTAL_SWAP = new Long(GEN_TOTAL_SWAP);\n    public static final long GEN_CPU_VENDOR_ID = 0x40L;\n    public static final Long LGEN_CPU_VENDOR_ID = new Long(GEN_CPU_VENDOR_ID);\n    public static final long GEN_CPU_FAMILY = 0x80L;\n    public static final Long LGEN_CPU_FAMILY = new Long(GEN_CPU_FAMILY);\n    public static final long GEN_CPU_MODEL = 0x100L;\n    public static final Long LGEN_CPU_MODEL = new Long(GEN_CPU_MODEL);\n    public static final long GEN_CPU_MODEL_NAME = 0x200L;\n    public static final Long LGEN_CPU_MODEL_NAME = new Long(GEN_CPU_MODEL_NAME);\n    public static final long GEN_BOGOMIPS = 0x400L;\n    public static final Long LGEN_BOGOMIPS = new Long(GEN_BOGOMIPS);\n    public static final long JOB_RUN_TIME = 0x1L;\n    public static final Long LJOB_RUN_TIME = new Long(JOB_RUN_TIME);\n    public static final long JOB_CPU_TIME = 0x2L;\n    public static final Long LJOB_CPU_TIME = new Long(JOB_CPU_TIME);\n    public static final long JOB_CPU_USAGE = 0x4L;\n    public static final Long LJOB_CPU_USAGE = new Long(JOB_CPU_USAGE);\n    public static final long JOB_MEM_USAGE = 0x8L;\n    public static final Long LJOB_MEM_USAGE = new Long(JOB_MEM_USAGE);\n    public static final long JOB_WORKDIR_SIZE = 0x10L;\n    public static final Long LJOB_WORKDIR_SIZE = new Long(JOB_WORKDIR_SIZE);\n    public static final long JOB_DISK_TOTAL = 0x20L;\n    public static final Long LJOB_DISK_TOTAL = new Long(SYS_CPU_IDLE);\n    public static final long JOB_DISK_USED = 0x40L;\n    public static final Long LJOB_DISK_USED = new Long(JOB_DISK_USED);\n    public static final long JOB_DISK_FREE = 0x80L;\n    public static final Long LJOB_DISK_FREE = new Long(JOB_DISK_FREE);\n    public static final long JOB_DISK_USAGE = 0x100L;\n\n    //JOB_*\n    public static final Long LJOB_DISK_USAGE = new Long(JOB_DISK_USAGE);\n    public static final long JOB_VIRTUALMEM = 0x200L;\n    public static final Long LJOB_VIRTUALMEM = new Long(JOB_VIRTUALMEM);\n    public static final long JOB_RSS = 0x400L;\n    public static final Long LJOB_RSS = new Long(JOB_RSS);\n    public static final long JOB_OPEN_FILES = 0x800L;\n    public static final Long LJOB_OPEN_FILES = new Long(JOB_OPEN_FILES);\n    static HashMap HT_SYS_NAMES_TO_CONSTANTS = null;\n    private static HashMap HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES = null;\n    private static HashMap HT_GEN_NAMES_TO_CONSTANTS = null;\n    private static HashMap HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES = null;\n    private static HashMap HT_JOB_NAMES_TO_CONSTANTS = null;\n    private static HashMap HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES = null;\n\n    static {\n        HT_SYS_NAMES_TO_CONSTANTS = new HashMap();\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_load1\", LSYS_LOAD1);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_load5\", LSYS_LOAD5);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_load15\", LSYS_LOAD15);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_cpu_usr\", LSYS_CPU_USR);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_cpu_sys\", LSYS_CPU_SYS);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_cpu_idle\", LSYS_CPU_IDLE);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_cpu_nice\", LSYS_CPU_NICE);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_cpu_usage\", LSYS_CPU_USAGE);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_mem_free\", LSYS_MEM_FREE);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_mem_used\", LSYS_MEM_USED);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_mem_usage\", LSYS_MEM_USAGE);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_pages_in\", LSYS_PAGES_IN);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_pages_out\", LSYS_PAGES_OUT);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_net_in\", LSYS_NET_IN);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_net_out\", LSYS_NET_OUT);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_net_errs\", LSYS_NET_ERRS);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_swap_free\", LSYS_SWAP_FREE);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_swap_used\", LSYS_SWAP_USED);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_swap_usage\", LSYS_SWAP_USAGE);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_processes\", LSYS_PROCESSES);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_net_sockets\", LSYS_NET_SOCKETS);\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_net_tcp_details\", LSYS_NET_TCP_DETAILS);\n\n        HT_SYS_NAMES_TO_CONSTANTS.put(\"sys_uptime\", LSYS_UPTIME);\n\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES = new HashMap();\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_LOAD1, \"load1\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_LOAD5, \"load5\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_LOAD15, \"load15\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_CPU_USR, \"cpu_usr\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_CPU_SYS, \"cpu_sys\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_CPU_IDLE, \"cpu_idle\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_CPU_NICE, \"cpu_nice\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_CPU_USAGE, \"cpu_usage\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_MEM_FREE, \"mem_free\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_MEM_USED, \"mem_used\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_MEM_USAGE, \"mem_usage\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_PAGES_IN, \"pages_in\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_PAGES_OUT, \"pages_out\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_NET_IN, \"in\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_NET_OUT, \"out\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_NET_ERRS, \"errs\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_SWAP_FREE, \"swap_free\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_SWAP_USED, \"swap_used\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_SWAP_USAGE, \"swap_usage\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_PROCESSES, \"processes\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_NET_SOCKETS, \"sockets\");\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_NET_TCP_DETAILS, \"sockets_tcp\");\n\n        HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES.put(LSYS_UPTIME, \"uptime\");\n\n    }\n\n    static {\n        HT_GEN_NAMES_TO_CONSTANTS = new HashMap();\n\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"hostname\", LGEN_HOSTNAME);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"ip\", LGEN_IP);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"cpu_MHz\", LGEN_CPU_MHZ);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"no_CPUs\", LGEN_NO_CPUS);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"total_mem\", LGEN_TOTAL_MEM);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"total_swap\", LGEN_TOTAL_SWAP);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"cpu_vendor_id\", LGEN_CPU_VENDOR_ID);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"cpu_family\", LGEN_CPU_FAMILY);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"cpu_model\", LGEN_CPU_MODEL);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"cpu_model_name\", LGEN_CPU_MODEL_NAME);\n        HT_GEN_NAMES_TO_CONSTANTS.put(\"bogomips\", LGEN_BOGOMIPS);\n\n\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES = new HashMap();\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_HOSTNAME, \"hostname\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_IP, \"ip\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_CPU_MHZ, \"cpu_MHZ\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_NO_CPUS, \"no_CPUs\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_TOTAL_MEM, \"total_mem\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_TOTAL_SWAP, \"total_swap\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_CPU_VENDOR_ID, \"cpu_vendor_id\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_CPU_FAMILY, \"cpu_family\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_CPU_MODEL, \"cpu_model\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_CPU_MODEL_NAME, \"cpu_model_name\");\n        HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES.put(LGEN_BOGOMIPS, \"bogomips\");\n    }\n\n    static {\n        HT_JOB_NAMES_TO_CONSTANTS = new HashMap();\n\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_run_time\", LJOB_RUN_TIME);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_cpu_time\", LJOB_CPU_TIME);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_cpu_usage\", LJOB_CPU_USAGE);\n\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_mem_usage\", LJOB_MEM_USAGE);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_workdir_size\", LJOB_WORKDIR_SIZE);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_disk_total\", LJOB_DISK_TOTAL);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_disk_used\", LJOB_DISK_USED);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_disk_free\", LJOB_DISK_FREE);\n\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_disk_usage\", LJOB_DISK_USAGE);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_virtualmem\", LJOB_VIRTUALMEM);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_rss\", LJOB_RSS);\n        HT_JOB_NAMES_TO_CONSTANTS.put(\"job_open_files\", LJOB_OPEN_FILES);\n\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES = new HashMap();\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_RUN_TIME, \"run_time\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_CPU_TIME, \"cpu_time\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_CPU_USAGE, \"cpu_usage\");\n\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_MEM_USAGE, \"mem_usage\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_WORKDIR_SIZE, \"workdir_size\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_DISK_TOTAL, \"disk_total\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_DISK_USED, \"disk_used\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_DISK_FREE, \"disk_free\");\n\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_DISK_USAGE, \"disk_usage\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_VIRTUALMEM, \"disk_virtualmem\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_RSS, \"disk_rss\");\n        HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES.put(LJOB_OPEN_FILES, \"open_files\");\n\n    }\n\n    //helper functions\n    private static String getName(Long param, HashMap hm) {\n        if (param == null) return null;\n        if (!hm.containsValue(param)) return null;\n\n        for (Iterator it = hm.keySet().iterator(); it.hasNext(); ) {\n            String key = (String) it.next();\n            if (hm.get(key).equals(param)) return key;\n        }\n\n        //should not get normally here .... but who knows :)\n        return null;\n    }\n\n    private static Long getIdx(String name, HashMap hm) {\n        if (name == null) return null;\n        return (Long) hm.get(name);\n    }\n\n    private static String getMLParamName(Long idx, HashMap hm) {\n        if (idx == null) return null;\n        return (String) hm.get(idx);\n    }\n\n    //this function can be slower ... it will be used only for debugging\n    public static String getSysName(Long param) {\n        return getName(param, HT_SYS_NAMES_TO_CONSTANTS);\n    }\n\n    public static Long getSysIdx(String name) {\n        return getIdx(name, HT_SYS_NAMES_TO_CONSTANTS);\n    }\n\n    public static String getSysMLParamName(Long idx) {\n        return getMLParamName(idx, HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n\n    public static String getSysMLParamName(long idx) {\n        return getMLParamName(new Long(idx), HT_SYS_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n\n    public static String getGenName(Long param) {\n        return getName(param, HT_GEN_NAMES_TO_CONSTANTS);\n    }\n\n    public static Long getGenIdx(String name) {\n        return getIdx(name, HT_GEN_NAMES_TO_CONSTANTS);\n    }\n\n    public static String getGenMLParamName(Long idx) {\n        return getMLParamName(idx, HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n\n    public static String getGenMLParamName(long idx) {\n        return getMLParamName(new Long(idx), HT_GEN_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n\n    public static String getJobName(Long param) {\n        return getName(param, HT_JOB_NAMES_TO_CONSTANTS);\n    }\n\n    public static Long getJobIdx(String name) {\n        return getIdx(name, HT_JOB_NAMES_TO_CONSTANTS);\n    }\n\n    public static String getJobMLParamName(Long idx) {\n        return getMLParamName(idx, HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n\n    public static String getJobMLParamName(long idx) {\n        return getMLParamName(new Long(idx), HT_JOB_CONSTANTS_TO_ML_PARAM_NAMES);\n    }\n}\n"
  },
  {
    "path": "src/apmon/BkThread.java",
    "content": "/*\n * ApMon - Application Monitoring Tool\n * Version: 2.2.7\n *\n * Copyright (C) 2006 - 2010 California Institute of Technology\n *\n * Permission is hereby granted, free of charge, to use, copy and modify \n * this software and its documentation (the \"Software\") for any\n * purpose, provided that existing copyright notices are retained in \n * all copies and that this notice is included verbatim in any distributions\n * or substantial portions of the Software. \n * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu).\n * Users of the Software are asked to feed back problems, benefits,\n * and/or suggestions about the software to the MonALISA Development Team\n * (developers@monalisa.cern.ch). Support for this software - fixing of bugs,\n * incorporation of new features - is done on a best effort basis. All bug\n * fixes and enhancements will be made available under the same terms and\n * conditions as the original software,\n \n * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR\n * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\n * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,\n * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS\n * PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO\n * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n * MODIFICATIONS.\n */\n\npackage apmon;\n\nimport apmon.host.HostPropertiesMonitor;\nimport apmon.host.Parser;\nimport apmon.host.cmdExec;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.*;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Separate thread which periodically checks the configuration file/URLs for changes and periodically sends datagrams\n * with monitoring information.\n */\nclass BkThread extends Thread {\n\n    /* types of operations that this thread executes */\n    public static final int RECHECK_CONF = 0;\n\n    public static final int SYS_INFO_SEND = 1;\n\n    public static final int JOB_INFO_SEND = 2;\n\n    static String osName = System.getProperty(\"os.name\");\n\n    private static Logger logger = Logger.getLogger(\"apmon\");\n\n    ApMon apm;\n\n    boolean hasToRun = true;\n\n    /* LISA object used for obtaining system monitoring information */\n    HostPropertiesMonitor monitor = null;\n\n    public BkThread(ApMon apm) {\n        this.apm = apm;\n        this.monitor = new HostPropertiesMonitor();\n        this.setDaemon(true);\n    }\n\n    public static Hashtable getCpuInfo() throws IOException, ApMonException {\n        if (osName.indexOf(\"Linux\") < 0)\n            return null;\n\n        Hashtable info = new Hashtable();\n\n        BufferedReader in = null;\n        FileReader fr = null;\n        try {\n            fr = new FileReader(\"/proc/cpuinfo\");\n            in = new BufferedReader(fr);\n            String line = null;\n            while ((line = in.readLine()) != null) {\n                StringTokenizer st = new StringTokenizer(line, \":\");\n                if (line.startsWith(\"cpu MHz\")) {\n                    st.nextToken();\n                    String freq_s = st.nextToken();\n                    if (freq_s == null)\n                        throw new ApMonException(\"Error reading CPU frequency from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_CPU_MHZ, freq_s);\n                }\n                if (line.startsWith(\"vendor_id\")) {\n                    st.nextToken();\n                    String vendor = st.nextToken();\n                    if (vendor == null)\n                        throw new ApMonException(\"Error reading CPU vendor_id from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_CPU_VENDOR_ID, vendor);\n                }\n                if (line.startsWith(\"model\") && !line.startsWith(\"model name\")) {\n                    st.nextToken();\n                    String model = st.nextToken();\n                    if (model == null)\n                        throw new ApMonException(\"Error reading CPU model from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_CPU_MODEL, model);\n                }\n                if (line.startsWith(\"cpu family\")) {\n                    st.nextToken();\n                    String cpufam = st.nextToken();\n                    if (cpufam == null)\n                        throw new ApMonException(\"Error reading CPU family from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_CPU_FAMILY, cpufam);\n                }\n                if (line.startsWith(\"model name\")) {\n                    st.nextToken();\n                    String modelname = st.nextToken();\n                    if (modelname == null)\n                        throw new ApMonException(\"Error reading CPU model name from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_CPU_MODEL_NAME, modelname);\n                }\n                if (line.startsWith(\"bogomips\")) {\n                    st.nextToken();\n                    String bogomips = st.nextToken();\n                    if (bogomips == null)\n                        throw new ApMonException(\"Error reading CPU bogomips from /proc/cpuinfo\");\n                    info.put(ApMonMonitoringConstants.LGEN_BOGOMIPS, bogomips);\n                }\n            }\n        } finally {\n            if (fr != null) {\n                try {\n                    fr.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            if (in != null) {\n                try {\n                    in.close();\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n        return info;\n    }\n\n    /**\n     * Returns the system boot time in milliseconds since the Epoch. Works only on Linux systems.\n     */\n    public static long getBootTime() throws IOException, ApMonException {\n        if (osName.indexOf(\"Linux\") < 0)\n            return 0;\n\n        BufferedReader in = null;\n        FileReader fr = null;\n        try {\n            fr = new FileReader(\"/proc/stat\");\n            in = new BufferedReader(fr);\n            String line = null;\n            while ((line = in.readLine()) != null) {\n                if (line.startsWith(\"btime\"))\n                    break;\n            }\n\n            if (line == null)\n                throw new ApMonException(\"Error reading boot time from /proc/stat\");\n\n            StringTokenizer st = new StringTokenizer(line);\n            st.nextToken();\n            String btime_s = st.nextToken();\n\n            if (btime_s == null)\n                throw new ApMonException(\"Error reading boot time from /proc/stat\");\n\n            return (Long.parseLong(btime_s) * 1000);\n        } finally {\n            if (fr != null) {\n                try {\n                    fr.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            if (in != null) {\n                try {\n                    in.close();\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n    }\n\n    /* in days */\n    public static double getUpTime() throws IOException, ApMonException {\n        if (osName.indexOf(\"Linux\") < 0)\n            return 0;\n\n        FileReader fr = null;\n        BufferedReader in = null;\n\n        try {\n            fr = new FileReader(\"/proc/uptime\");\n            in = new BufferedReader(fr);\n            String line = in.readLine();\n            if (line == null)\n                throw new ApMonException(\"Error reading boot time from /proc/uptime\");\n\n            StringTokenizer st = new StringTokenizer(line);\n            String up_time = st.nextToken();\n\n            if (up_time == null)\n                throw new ApMonException(\"Error reading optime from /proc/uptime\");\n\n            return (Double.parseDouble(up_time)) / (3600 * 24);\n        } finally {\n            if (fr != null) {\n                try {\n                    fr.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            if (in != null) {\n                try {\n                    in.close();\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n\n    }\n\n    /**\n     * Returns the number of CPUs in the system\n     */\n    public static int getNumCPUs() throws IOException, ApMonException {\n        if (osName.indexOf(\"Linux\") < 0)\n            return 0;\n\n        FileReader fr = null;\n        BufferedReader in = null;\n        try {\n            fr = new FileReader(\"/proc/stat\");\n            in = new BufferedReader(fr);\n            String line = null;\n            int numCPUs = 0;\n            while ((line = in.readLine()) != null) {\n                if (line.startsWith(\"cpu\") && Character.isDigit(line.charAt(3)))\n                    numCPUs++;\n            }\n\n            if (numCPUs == 0)\n                throw new ApMonException(\"Error reading CPU frequency from /proc/stat\");\n\n            return numCPUs;\n        } finally {\n            if (fr != null) {\n                try {\n                    fr.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            if (in != null) {\n                try {\n                    in.close();\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n    }\n\n    public static void getNetConfig(Vector netInterfaces, Vector ips) throws IOException, ApMonException {\n        String line;\n        Parser parser = new Parser();\n        cmdExec exec = new cmdExec();\n\n        String output = exec.executeCommandReality(\"/sbin/ifconfig -a\", \"\");\n        if (exec.isError())\n            output = null;\n        exec.stopIt();\n\n        String crtIfaceName = null;\n        if (output != null && !output.equals(\"\")) {\n            parser.parse(output);\n            line = parser.nextLine();\n            while (line != null) {\n                if (line == null)\n                    break;\n                StringTokenizer lst = new StringTokenizer(line, \" :\\t\");\n                if (line.startsWith(\" \") || line.startsWith(\"\\t\")) {\n                    if (line.indexOf(\"inet\") < 0) {\n                        line = parser.nextLine();\n                        continue;\n                    }\n\n                    lst.nextToken();\n                    lst.nextToken();\n                    String addr_t = lst.nextToken();\n                    if (!addr_t.equals(\"127.0.0.1\")) {\n                        ips.add(addr_t);\n                        netInterfaces.add(crtIfaceName);\n                    }\n                } else {\n                    // get the name\n                    String netName = lst.nextToken();\n                    if (netName != null && !netName.startsWith(\"lo\") && netName.indexOf(\"eth\") != -1) {\n                        crtIfaceName = new String(netName);\n                    }\n                }\n\n                line = parser.nextLine();\n            }\n        }\n\n    }\n\n    void stopIt() {\n        hasToRun = false;\n    }\n\n    /**\n     * Returns true if the given parameter is set to be included in the system monitoring packet.\n     */\n    boolean isActive_Sys(long param) {\n        return ((apm.sysMonitorParams & param) == param);\n    }\n\n    boolean isActive_Sys(Long param) {\n        return isActive_Sys(param.longValue());\n    }\n\n    /**\n     * Returns true if the given parameter is set to be included in the job monitoring packet.\n     */\n    boolean isActive_Job(long param) {\n        return ((apm.jobMonitorParams & param) == param);\n    }\n\n    boolean isActive_Job(Long param) {\n        return isActive_Job(param.longValue());\n    }\n\n    /**\n     * Returns true if the given parameter is set to be included in the general system monitoring packet.\n     */\n    boolean isActive_Gen(long param) {\n        return ((apm.genMonitorParams & param) == param);\n    }\n\n    boolean isActive_Gen(Long param) {\n        return isActive_Gen(param.longValue());\n    }\n\n    void sendJobInfo() {\n        int i;\n\n        synchronized (apm.mutexBack) {\n\n            if (apm.monJobs.size() == 0) {\n                logger.warning(\"There are not jobs to be monitored, not sending job monitoring information...\");\n                return;\n            }\n            Date d = new Date();\n            logger.info(\"Sending job monitoring information...\");\n            apm.lastJobInfoSend = d.getTime();\n\n            for (i = 0; i < apm.monJobs.size(); i++)\n                sendOneJobInfo(((MonitoredJob) apm.monJobs.get(i)));\n        }\n    }\n\n    /**\n     * Sends an UDP datagram with job monitoring information. Works only in Linux system; on other systems it takes no\n     * action.\n     */\n    void sendOneJobInfo(MonitoredJob monJob) {\n\n        Vector paramNames, paramValues;\n        // , valueTypes;\n\n        long crtTime = System.currentTimeMillis();\n\n        apm.lastJobInfoSend = crtTime;\n\n        paramNames = new Vector();\n        paramValues = new Vector();\n        // valueTypes = new Vector();\n\n        HashMap hmJobInfo = null;\n\n        try {\n            hmJobInfo = monJob.readJobInfo();\n        } catch (IOException e) {\n            logger.warning(\"Unable to read job info for \" + monJob.getPid());\n            hmJobInfo = null;\n        }\n\n        if (hmJobInfo == null) {\n            logger.warning(\"Job \" + monJob.pid + \" does not exist\");\n            apm.removeJobToMonitor(monJob.pid);\n            return;\n        }\n\n        HashMap hmJobDisk = null;\n\n        try {\n            hmJobDisk = monJob.readJobDiskUsage();\n        } catch (Throwable t1) {\n            logger.warning(\"Unable to read job Disk Usage info for \" + monJob.getPid());\n            hmJobDisk = null;\n        }\n\n        // hmJobInfo != null FOR SURE!\n        HashMap hm = hmJobInfo;\n\n        if (hmJobDisk != null) {\n            hm.putAll(hmJobDisk);\n        }\n\n        for (Iterator it = hm.keySet().iterator(); it.hasNext(); ) {\n            Long lParam = (Long) it.next();\n            try {\n                if (isActive_Job(lParam)) {\n                    Double val = (Double) hm.get(lParam);\n                    paramNames.add(ApMonMonitoringConstants.getJobMLParamName(lParam));\n                    paramValues.add(val);\n                    // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring) {\n                    logger.warning(\"parameter \" + ApMonMonitoringConstants.getJobName(lParam) + \" disabled\");\n                    apm.sysMonitorParams &= ~lParam.longValue();\n                }\n            }\n        }\n\n        try {\n            apm.sendParameters(monJob.clusterName, monJob.nodeName, paramNames.size(), paramNames, paramValues);\n        } catch (Exception e) {\n            logger.warning(\"Error while sending system information: \" + e);\n        }\n    }\n\n    /**\n     * Sends an UDP datagram with system monitoring information\n     */\n    void sendSysInfo() {\n        double value = 0.0;\n        Vector paramNames, paramValues;\n        // , valueTypes;\n\n        monitor.updateCall();\n        long crtTime = System.currentTimeMillis();\n\n        logger.log(Level.FINER,\"Sending system monitoring information...\");\n        // long intervalLength = crtTime - apm.lastSysInfoSend;\n        apm.lastSysInfoSend = crtTime;\n\n        paramNames = new Vector();\n        paramValues = new Vector();\n        // valueTypes = new Vector();\n\n        HashMap hms = monitor.getHashParams();\n\n        if (hms != null) {\n            for (Iterator it = hms.keySet().iterator(); it.hasNext(); ) {\n                Long lParam = (Long) it.next();\n                try {\n                    if (isActive_Sys(lParam)) {\n                        Double val = Double.valueOf((String) hms.get(lParam));\n                        paramNames.add(ApMonMonitoringConstants.getSysMLParamName(lParam));\n                        paramValues.add(val);\n                        // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n                    }\n                } catch (Throwable t) {\n                    if (apm.autoDisableMonitoring) {\n                        logger.warning(\"parameter \" + ApMonMonitoringConstants.getSysName(lParam) + \" disabled\");\n                        apm.sysMonitorParams &= ~lParam.longValue();\n                    }\n                }\n            }\n        }\n\n        if (apm.netInterfaces != null && apm.netInterfaces.size() != 0) {\n            for (int i = 0; i < apm.netInterfaces.size(); i++) {\n                String iName = (String) apm.netInterfaces.get(i);\n                if (iName == null)\n                    continue;\n                try {\n                    if (isActive_Sys(ApMonMonitoringConstants.SYS_NET_IN)) {\n                        value = Double.parseDouble(monitor.getNetInCall(iName));\n                        if (osName.indexOf(\"Mac\") == -1)\n                            // measure in KBps\n                            value = value * 1024;\n                        paramNames.add(iName + \"_\" + ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_NET_IN));\n                        paramValues.add(new Double(value));\n                        // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"\", t);\n                    // should not disable ... can work for the other interfaces\n                }\n\n                try {\n                    if (isActive_Sys(ApMonMonitoringConstants.SYS_NET_OUT)) {\n                        value = Double.parseDouble(monitor.getNetOutCall(iName));\n                        if (osName.indexOf(\"Mac\") == -1)\n                            // measure in KBps\n                            value = value * 1024;\n                        paramNames.add(iName + \"_\" + ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_NET_OUT));\n                        paramValues.add(new Double(value));\n                        // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"\", t);\n                    ;\n                    // should not disable ... can work for the other interfaces\n                }\n            }\n        }\n\n        if (isActive_Sys(ApMonMonitoringConstants.SYS_UPTIME)) {\n            try {\n                value = getUpTime();\n                paramNames.add(ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_UPTIME));\n                paramValues.add(new Double(value));\n                // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n            } catch (Exception e) {\n                logger.log(Level.WARNING, \"\", e);\n                ;\n                if (apm.autoDisableMonitoring) {\n                    logger.warning(\"parameter sys_uptime disabled\");\n                    apm.sysMonitorParams &= ~ApMonMonitoringConstants.SYS_UPTIME;\n                }\n            }\n        }\n\n        if (isActive_Sys(ApMonMonitoringConstants.SYS_PROCESSES)) {\n            try {\n                Hashtable vals = monitor.getPState();\n                Enumeration e = vals.keys();\n                while (e.hasMoreElements()) {\n                    String name = (String) e.nextElement();\n                    Integer val = (Integer) vals.get(name);\n                    paramNames.add(ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_PROCESSES) + \"_\" + name);\n                    paramValues.add(val);\n                    // valueTypes.add(new Integer(ApMon.XDR_INT32));\n                }\n            } catch (Exception e) {\n                logger.log(Level.WARNING, \"\", e);\n                ;\n                if (apm.autoDisableMonitoring) {\n                    logger.warning(\"parameter processes disabled\");\n                    apm.sysMonitorParams &= ~ApMonMonitoringConstants.SYS_PROCESSES;\n                }\n            }\n        }\n\n        if (isActive_Sys(ApMonMonitoringConstants.SYS_NET_SOCKETS)) {\n            try {\n                Hashtable vals = monitor.getSockets();\n                Enumeration e = vals.keys();\n                while (e.hasMoreElements()) {\n                    String name = (String) e.nextElement();\n                    Integer val = (Integer) vals.get(name);\n                    paramNames.add(ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_NET_SOCKETS) + \"_\" + name);\n                    paramValues.add(val);\n                    // valueTypes.add(new Integer(ApMon.XDR_INT32));\n                }\n            } catch (Exception e) {\n                logger.log(Level.WARNING, \"\", e);\n                ;\n                if (apm.autoDisableMonitoring) {\n                    logger.warning(\"parameter processes disabled\");\n                    apm.sysMonitorParams &= ~ApMonMonitoringConstants.SYS_NET_SOCKETS;\n                }\n            }\n        }\n\n        if (isActive_Sys(ApMonMonitoringConstants.SYS_NET_TCP_DETAILS)) {\n            try {\n                Hashtable vals = monitor.getTCPDetails();\n                Enumeration e = vals.keys();\n                while (e.hasMoreElements()) {\n                    String name = (String) e.nextElement();\n                    Integer val = (Integer) vals.get(name);\n                    paramNames.add(ApMonMonitoringConstants.getSysMLParamName(ApMonMonitoringConstants.SYS_NET_TCP_DETAILS) + \"_\" + name);\n                    paramValues.add(val);\n                    // valueTypes.add(new Integer(ApMon.XDR_INT32));\n                }\n            } catch (Exception e) {\n                logger.log(Level.WARNING, \"\", e);\n                if (apm.autoDisableMonitoring) {\n                    logger.warning(\"parameter processes disabled\");\n                    apm.sysMonitorParams &= ~ApMonMonitoringConstants.SYS_NET_TCP_DETAILS;\n                }\n            }\n        }\n\n        try {\n            apm.sendParameters(apm.sysClusterName, apm.sysNodeName, paramNames.size(), paramNames, paramValues);\n        } catch (Exception e) {\n            logger.warning(\"Error while sending system information: \" + e);\n        }\n    }\n\n    /**\n     * Sends an UDP datagram with general system monitoring information. Only works with Linux systems; on other systems\n     * it is disabled.\n     */\n    void sendGeneralInfo() {\n        Vector paramNames, paramValues;\n        // , valueTypes;\n        double cpu_MHz, bogomips;\n        int no_CPUs, i;\n\n        paramNames = new Vector();\n        paramValues = new Vector();\n        // valueTypes = new Vector();\n\n        paramNames.add(\"hostname\");\n        paramValues.add(apm.myHostname);\n        // valueTypes.add(new Integer(ApMon.XDR_STRING));\n        for (i = 0; i < apm.netInterfaces.size(); i++) {\n            try {\n                paramNames.add(\"ip_\" + apm.netInterfaces.get(i));\n                paramValues.add(apm.allMyIPs.get(i));\n                // valueTypes.add(new Integer(ApMon.XDR_STRING));\n            } catch (Exception e) {\n                logger.log(Level.FINE, \"BkThread got exception, ignoring network interface: \", e);\n            }\n        }\n\n        Hashtable cpuInfo = new Hashtable();\n        try {\n            cpuInfo = getCpuInfo();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_CPU_MHZ)) {\n            try {\n                cpu_MHz = Double.parseDouble((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_CPU_MHZ));\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_CPU_MHZ));\n                paramValues.add(new Double(cpu_MHz));\n                // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_CPU_MHZ;\n            }\n        }\n\n        String val;\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_CPU_VENDOR_ID)) {\n            try {\n                val = ((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_CPU_VENDOR_ID)).trim();\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_CPU_VENDOR_ID));\n                paramValues.add(val);\n                // valueTypes.add(new Integer(ApMon.XDR_STRING));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_CPU_VENDOR_ID;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_CPU_FAMILY)) {\n            try {\n                val = ((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_CPU_FAMILY)).trim();\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_CPU_FAMILY));\n                paramValues.add(val);\n                // valueTypes.add(new Integer(ApMon.XDR_STRING));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_CPU_FAMILY;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_CPU_MODEL)) {\n            try {\n                val = ((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_CPU_MODEL)).trim();\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_CPU_MODEL));\n                paramValues.add(val);\n                // valueTypes.add(new Integer(ApMon.XDR_STRING));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_CPU_MODEL;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_CPU_MODEL_NAME)) {\n            try {\n                val = ((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_CPU_MODEL_NAME)).trim();\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_CPU_MODEL_NAME));\n                paramValues.add(val);\n                // valueTypes.add(new Integer(ApMon.XDR_STRING));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_CPU_MODEL_NAME;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_BOGOMIPS)) {\n            try {\n                bogomips = Double.parseDouble((String) cpuInfo.get(ApMonMonitoringConstants.LGEN_BOGOMIPS));\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_BOGOMIPS));\n                paramValues.add(new Double(bogomips));\n                // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_BOGOMIPS;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_NO_CPUS)) {\n            try {\n                no_CPUs = getNumCPUs();\n                paramNames.add(ApMonMonitoringConstants.getGenMLParamName(ApMonMonitoringConstants.LGEN_NO_CPUS));\n                paramValues.add(new Integer(no_CPUs));\n                // valueTypes.add(new Integer(ApMon.XDR_INT32));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_NO_CPUS;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_TOTAL_MEM)) {\n            try {\n                Double tm = Double.valueOf(monitor.getMemTotalCall());\n                paramNames.add(ApMonMonitoringConstants.getGenName(ApMonMonitoringConstants.LGEN_TOTAL_MEM));\n                paramValues.add(tm);\n                // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                ;\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_TOTAL_MEM;\n            }\n        }\n\n        if (isActive_Gen(ApMonMonitoringConstants.GEN_TOTAL_SWAP)) {\n            try {\n                Double tm = Double.valueOf(monitor.getSwapTotalCall());\n                paramNames.add(ApMonMonitoringConstants.getGenName(ApMonMonitoringConstants.LGEN_TOTAL_SWAP));\n                paramValues.add(tm);\n                // valueTypes.add(new Integer(ApMon.XDR_REAL64));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\", t);\n                ;\n                if (apm.autoDisableMonitoring)\n                    apm.genMonitorParams &= ~ApMonMonitoringConstants.GEN_TOTAL_SWAP;\n            }\n        }\n\n        try {\n            apm.sendParameters(apm.sysClusterName, apm.sysNodeName, paramNames.size(), paramNames, paramValues);\n        } catch (Exception e) {\n            logger.warning(\"Error while sending general system information: \" + e);\n        }\n    }\n\n    public void run() {\n        long crtTime, timeRemained, nextOpTime;\n        long nextRecheck = 0, nextJobInfoSend = 0, nextSysInfoSend = 0;\n        int generalInfoCount;\n        int nextOp = 0;\n        boolean haveChange, haveTimeout;\n        logger.info(\"[Starting background thread...]\");\n\n        crtTime = System.currentTimeMillis();\n\n        synchronized (apm.mutexBack) {\n            if (apm.confCheck) {\n                nextRecheck = crtTime + apm.crtRecheckInterval * 1000;\n            }\n            if (apm.jobMonitoring)\n                nextJobInfoSend = crtTime + apm.jobMonitorInterval * 1000;\n            if (apm.sysMonitoring)\n                nextSysInfoSend = crtTime + apm.sysMonitorInterval * 1000;\n        }\n        timeRemained = nextOpTime = -1;\n        generalInfoCount = 0;\n\n        while (hasToRun) {\n            crtTime = System.currentTimeMillis();\n\n            /* determine the next operation that must be performed */\n            if (nextRecheck > 0 && (nextJobInfoSend <= 0 || nextRecheck <= nextJobInfoSend)) {\n                if (nextSysInfoSend <= 0 || nextRecheck <= nextSysInfoSend) {\n                    nextOp = RECHECK_CONF;\n                    nextOpTime = nextRecheck;\n                } else {\n                    nextOp = SYS_INFO_SEND;\n                    nextOpTime = nextSysInfoSend;\n                }\n            } else {\n                if (nextJobInfoSend > 0 && (nextSysInfoSend <= 0 || nextJobInfoSend <= nextSysInfoSend)) {\n                    nextOp = JOB_INFO_SEND;\n                    nextOpTime = nextJobInfoSend;\n                } else if (nextSysInfoSend > 0) {\n                    nextOp = SYS_INFO_SEND;\n                    nextOpTime = nextSysInfoSend;\n                }\n            }\n\n            if (nextOpTime == -1)\n                nextOpTime = crtTime + ApMon.RECHECK_INTERVAL * 1000;\n\n            synchronized (apm.mutexCond) {\n                synchronized (apm.mutexBack) {\n                    /* check for changes in the settings */\n                    haveChange = false;\n                    if (apm.jobMonChanged || apm.sysMonChanged || apm.recheckChanged)\n                        haveChange = true;\n                    if (apm.jobMonChanged) {\n                        if (apm.jobMonitoring)\n                            nextJobInfoSend = crtTime + apm.jobMonitorInterval * 1000;\n                        else\n                            nextJobInfoSend = -1;\n                        apm.jobMonChanged = false;\n                    }\n                    if (apm.sysMonChanged) {\n                        if (apm.sysMonitoring)\n                            nextSysInfoSend = crtTime + apm.sysMonitorInterval * 1000;\n                        else\n                            nextSysInfoSend = -1;\n                        apm.sysMonChanged = false;\n                    }\n                    if (apm.recheckChanged) {\n                        if (apm.confCheck)\n                            nextRecheck = crtTime + apm.crtRecheckInterval * 1000;\n                        else\n                            nextRecheck = -1;\n                        apm.recheckChanged = false;\n                    }\n                } // synchronized(apm.mutexBack)\n\n                if (haveChange)\n                    continue;\n\n                timeRemained = nextOpTime - System.currentTimeMillis();\n                haveTimeout = true;\n                /*\n                 * wait until the next operation should be performed or until a change in the settings occurs\n                 */\n                try {\n                    if (timeRemained > 0)\n                        apm.mutexCond.wait(timeRemained);\n                } catch (InterruptedException e) {\n                }\n\n                if (apm.condChanged) {\n                    haveTimeout = false;\n                }\n                apm.condChanged = false;\n            }\n            // logger.info(\"### have timeout \" + haveTimeout);\n            crtTime = System.currentTimeMillis();\n            // System.out.println(\"### 3 crtTime \" + crtTime + \" nextOpTime \" + nextOpTime);\n\n            if (haveTimeout) { // the time interval until the next operation expired\n                /* now perform the operation */\n                if (nextOp == JOB_INFO_SEND) {\n                    sendJobInfo();\n                    nextJobInfoSend = crtTime + apm.getJobMonitorInterval() * 1000;\n                }\n\n                if (nextOp == SYS_INFO_SEND) {\n                    sendSysInfo();\n                    if (apm.getGenMonitoring()) {\n                        /*\n                         * send only 2 general monitoring packets in genMonitorIntervals intervals\n                         */\n                        if (generalInfoCount <= 1)\n                            sendGeneralInfo();\n                        generalInfoCount = (generalInfoCount + 1) % apm.genMonitorIntervals;\n                    }\n                    nextSysInfoSend = crtTime + apm.getSysMonitorInterval() * 1000;\n                }\n\n                if (nextOp == RECHECK_CONF) {\n                    /* check all the configuration resources (file, URLs) */\n                    Enumeration e = apm.confResources.keys();\n                    boolean resourceChanged = false;\n\n                    try {\n                        while (e.hasMoreElements()) {\n                            Object obj = e.nextElement();\n\n                            Long lastModified = (Long) apm.confResources.get(obj);\n                            if (obj instanceof File) {\n                                File f = (File) obj;\n                                logger.info(\" [Checking for modifications for \" + f.getCanonicalPath() + \"]\");\n\n                                long lmt = f.lastModified();\n                                if (lmt > lastModified.longValue()) {\n                                    logger.info(\"[File \" + f.getCanonicalPath() + \" modified]\");\n                                    resourceChanged = true;\n                                    break;\n                                    // confResources.put(f, new Long(lmt));\n                                }\n                            }\n\n                            if (obj instanceof URL) {\n                                URL u = (URL) obj;\n                                long lmt = 0;\n\n                                logger.info(\"[Checking for modifications for \" + u + \"]\");\n                                URLConnection urlConn = u.openConnection();\n                                lmt = urlConn.getLastModified();\n\n                                if (lmt > lastModified.longValue() || lmt == 0) {\n                                    logger.info(\"[Location \" + u + \" modified]\");\n                                    resourceChanged = true;\n                                    break;\n                                }\n                            }\n                        } // while\n\n                        /*\n                         * if any resource has changed we have to recheck all the others, otherwise some destinations\n                         * might be ommitted\n                         */\n                        if (resourceChanged) {\n                            if (apm.initType == ApMon.FILE_INIT) {\n                                apm.initialize((String) apm.initSource, false);\n                            }\n\n                            if (apm.initType == ApMon.LIST_INIT) {\n                                apm.initialize((Vector) apm.initSource, false);\n                            }\n                        }\n                        apm.setCrtRecheckInterval(apm.getRecheckInterval());\n                    } catch (Throwable exc) {\n                        apm.setCrtRecheckInterval(10 * apm.getRecheckInterval());\n                    }\n                    crtTime = System.currentTimeMillis();\n                    nextRecheck = crtTime + apm.getRecheckInterval() * 1000;\n                } // while\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/apmon/MonitoredJob.java",
    "content": "/*\n * ApMon - Application Monitoring Tool\n * Version: 2.2.7\n *\n * Copyright (C) 2006 - 2010 California Institute of Technology\n *\n * Permission is hereby granted, free of charge, to use, copy and modify \n * this software and its documentation (the \"Software\") for any\n * purpose, provided that existing copyright notices are retained in \n * all copies and that this notice is included verbatim in any distributions\n * or substantial portions of the Software. \n * This software is a part of the MonALISA framework (http://monalisa.cacr.caltech.edu).\n * Users of the Software are asked to feed back problems, benefits,\n * and/or suggestions about the software to the MonALISA Development Team\n * (developers@monalisa.cern.ch). Support for this software - fixing of bugs,\n * incorporation of new features - is done on a best effort basis. All bug\n * fixes and enhancements will be made available under the same terms and\n * conditions as the original software,\n \n * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR\n * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\n * OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,\n * EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n \n * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,\n * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS\n * PROVIDED ON AN \"AS IS\" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO\n * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR\n * MODIFICATIONS.\n */\n\npackage apmon;\n\nimport apmon.host.cmdExec;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.StringTokenizer;\nimport java.util.Vector;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic class MonitoredJob {\n    private static Logger logger = Logger.getLogger(\"apmon\");\n    int pid;\n    /* the job's working dierctory */\n    String workDir;\n    /* the cluster name that will be included in the monitoring datagrams */\n    String clusterName;\n    /* the node name that will be included in the monitoring datagrams */\n    String nodeName;\n    cmdExec exec = null;\n\n    public MonitoredJob(int _pid, String _workDir, String _clusterName, String _nodeName) {\n        pid = _pid;\n        workDir = _workDir;\n        clusterName = _clusterName;\n        nodeName = _nodeName;\n        exec = new cmdExec();\n    }\n\n    public static long parsePSTime(String s) {\n        long days, hours, mins, secs;\n        if (s.indexOf('-') > 0) {\n            StringTokenizer st = new StringTokenizer(s, \"-:\");\n            days = Long.parseLong(st.nextToken());\n            hours = Long.parseLong(st.nextToken());\n            mins = Long.parseLong(st.nextToken());\n            secs = Long.parseLong(st.nextToken());\n            return 24 * 3600 * days + 3600 * hours + 60 * mins + secs;\n        }\n        if (s.indexOf(':') > 0 && s.indexOf(':') != s.lastIndexOf(':')) {\n            StringTokenizer st = new StringTokenizer(s, \":\");\n            hours = Long.parseLong(st.nextToken());\n            mins = Long.parseLong(st.nextToken());\n            secs = Long.parseLong(st.nextToken());\n            return 3600 * hours + 60 * mins + secs;\n        }\n\n        if (s.indexOf(':') > 0) {\n            StringTokenizer st = new StringTokenizer(s, \":\");\n            mins = Long.parseLong(st.nextToken());\n            secs = Long.parseLong(st.nextToken());\n            return 60 * mins + secs;\n        }\n\n        return -1;\n    }\n\n    public int getPid() {\n        return pid;\n    }\n\n    public HashMap readJobDiskUsage() {\n        HashMap hm = new HashMap();\n        String cmd = null, aux = null, line = null, result = null;\n        double workdir_size = 0.0, disk_total = 0.0, disk_used = 0.0, disk_free = 0.0, disk_usage = 0.0;\n\n        if (workDir == null)\n            return null;\n\n        cmd = \"du -Lscm \" + workDir + \" | tail -1 | cut -f 1\";\n        result = exec.executeCommandReality(cmd, \"\");\n        workdir_size = Double.parseDouble(result);\n        hm.put(ApMonMonitoringConstants.LJOB_WORKDIR_SIZE, new Double(workdir_size));\n\n        cmd = \"df -m \" + workDir + \" | tail -1\";\n        result = exec.executeCommand(cmd, \"\");\n        StringTokenizer st = new StringTokenizer(result, \" %\");\n        st.nextToken();\n\n        aux = st.nextToken();\n        disk_total = Double.parseDouble(aux);\n        hm.put(ApMonMonitoringConstants.LJOB_DISK_TOTAL, new Double(workdir_size));\n\n        aux = st.nextToken();\n        disk_used = Double.parseDouble(aux);\n        hm.put(ApMonMonitoringConstants.LJOB_DISK_USED, new Double(workdir_size));\n\n        aux = st.nextToken();\n        disk_free = Double.parseDouble(aux);\n        hm.put(ApMonMonitoringConstants.LJOB_DISK_FREE, new Double(workdir_size));\n\n        aux = st.nextToken();\n        disk_usage = Double.parseDouble(aux);\n        hm.put(ApMonMonitoringConstants.LJOB_DISK_USAGE, new Double(workdir_size));\n\n        return hm;\n    }\n\n    public Vector getChildren() {\n        Vector pids, ppids, children;\n        String cmd = null, result = null;\n        int nProcesses = 0, nChildren = 1;\n        int i, j;\n\n        cmd = \"ps --no-headers -eo ppid,pid\";\n        result = exec.executeCommandReality(cmd, \"\");\n        boolean pidFound = false;\n        if (result == null) {\n            logger.warning(\"The child processes could not be determined\");\n            return null;\n        }\n\n        StringTokenizer st = new StringTokenizer(result, \" \\n\");\n        nProcesses = st.countTokens() / 2;\n\n        pids = new Vector();\n        ppids = new Vector();\n        children = new Vector();\n        children.add(new Integer(pid));\n        while (st.hasMoreTokens()) {\n            i = Integer.parseInt(st.nextToken());\n            j = Integer.parseInt(st.nextToken());\n            if (j == pid)\n                pidFound = true;\n            ppids.add(new Integer(i));\n            pids.add(new Integer(j));\n            if (i == ((Integer) children.elementAt(0)).intValue()) {\n                children.add(new Integer(j));\n                nChildren++;\n            }\n        }\n\n        if (!pidFound)\n            return null;\n\n        i = 1;\n\n        while (i < nChildren) {\n            /* find the children of the i-th child */\n            for (j = 0; j < nProcesses; j++) {\n                if (ppids.elementAt(j).equals(children.elementAt(i))) {\n                    children.add(pids.elementAt(j));\n                    nChildren++;\n                }\n            }\n            i++;\n        }\n\n        return children;\n    }\n\n    public HashMap readJobInfo() throws IOException {\n        Vector children;\n        HashMap ret = new HashMap();\n        String cmd = null, result = null;\n        BufferedReader fp;\n        String line = null;\n\n        int i;\n\n        double rsz = 0.0, vsz = 0.0;\n        double etime = 0.0, cputime = 0.0;\n        double pcpu = 0.0, pmem = 0.0;\n\n        double _rsz, _vsz;\n        double _etime, _cputime;\n        double _pcpu, _pmem;\n\n        long apid, fd = 0;\n\n\t\t/*\n\t\t * this list contains strings of the form \"rsz_vsz_command\" for every pid; it is used to avoid adding several times processes that have multiple threads and appear in ps as\n\t\t * sepparate processes, occupying exactly the same amount of memory and having the same command name. For every line from the output of the ps command we verify if the\n\t\t * rsz_vsz_command combination is already in the list.\n\t\t */\n        Vector mem_cmd_list = new Vector();\n\n\t\t/* get the list of the process' descendants */\n        children = getChildren();\n\n        if (children == null)\n            return null;\n\n        logger.fine(\"Number of children for process \" + pid + \": \" + children.size());\n\n\t\t/* issue the \"ps\" command to obtain information on all the descendants */\n        cmd = \"ps --no-headers --pid \";\n        for (i = 0; i < children.size() - 1; i++)\n            cmd = cmd + children.elementAt(i) + \",\";\n        cmd = cmd + children.elementAt(children.size() - 1);\n\n        cmd = cmd + \" -o pid,etime,time,%cpu,%mem,rsz,vsz,comm\";\n        result = exec.executeCommandReality(cmd, \"\");\n\n        StringTokenizer rst = new StringTokenizer(result, \"\\n\");\n        while (rst.hasMoreTokens()) {\n            line = rst.nextToken();\n            StringTokenizer st = new StringTokenizer(line, \" \\t\");\n\n            apid = Long.parseLong(st.nextToken());\n            _etime = (double) parsePSTime(st.nextToken());\n            _cputime = (double) parsePSTime(st.nextToken());\n            _pcpu = Double.parseDouble(st.nextToken());\n            _pmem = Double.parseDouble(st.nextToken());\n            _rsz = Double.parseDouble(st.nextToken());\n            _vsz = Double.parseDouble(st.nextToken());\n            String cmdName = st.nextToken();\n\n            etime = etime > _etime ? etime : _etime;\n            cputime += _cputime;\n            pcpu += _pcpu;\n\n            String mem_cmd_s = \"\" + _rsz + \"_\" + _vsz + \"_\" + cmdName;\n            // mem_cmd_list.add(mem_cmd_s);\n            if (mem_cmd_list.indexOf(mem_cmd_s) == -1) {\n                pmem += _pmem;\n                vsz += _vsz;\n                rsz += _rsz;\n                mem_cmd_list.add(mem_cmd_s);\n                long _fd = countOpenFD(apid);\n                if (_fd != -1)\n                    fd += _fd;\n            }\n        }\n\n        ret.put(ApMonMonitoringConstants.LJOB_RUN_TIME, new Double(etime));\n        ret.put(ApMonMonitoringConstants.LJOB_CPU_TIME, new Double(cputime));\n        ret.put(ApMonMonitoringConstants.LJOB_CPU_USAGE, new Double(pcpu));\n        ret.put(ApMonMonitoringConstants.LJOB_MEM_USAGE, new Double(pmem));\n        ret.put(ApMonMonitoringConstants.LJOB_RSS, new Double(rsz));\n        ret.put(ApMonMonitoringConstants.LJOB_VIRTUALMEM, new Double(vsz));\n        ret.put(ApMonMonitoringConstants.LJOB_OPEN_FILES, new Double(fd));\n\n        return ret;\n    }\n\n    /**\n     * count the number of open files for the given pid\n     */\n    public long countOpenFD(long pid) {\n\n        long open_files;\n        int mypid = ApMon.getPID();\n        String dir = \"/proc/\" + pid + \"/fd\";\n        File f = new File(dir);\n        if (f.exists()) {\n            if (f.canRead()) {\n                open_files = (f.list()).length - 2;\n                if (pid == mypid)\n                    open_files -= 2;\n                logger.log(Level.FINE, \"Counting open_files for process \" + pid);\n            } else {\n                open_files = -1;\n                logger.log(Level.SEVERE, \"ProcInfo: cannot count the number of opened files for job\" + pid);\n            }\n        } else {\n            open_files = -1;\n            logger.log(Level.SEVERE, \"ProcInfo: job \" + pid + \"not exist.\");\n        }\n        return open_files;\n    }\n\n\n    public String toString() {\n        return new String(\"[\" + pid + \"]\" + \" \" + workDir + \" \" + \" \" + clusterName + \" \" + nodeName);\n    }\n\n}\n"
  },
  {
    "path": "src/apmon/XDRDataOutput.java",
    "content": "package apmon;\n\nimport java.io.DataOutput;\nimport java.io.IOException;\n\n\n/**\n * An interface implemented by output streams that support XDR.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n * @version $Id: XDRDataOutput.java,v 1.1.1.1 2005-08-10 12:51:21 catac Exp $\n */\npublic interface XDRDataOutput extends DataOutput {\n    void pad() throws IOException;\n\n    void writeDoubleArray(double[] array) throws IOException;\n\n    void writeDoubleArray(double[] array, int start, int n) throws IOException;\n\n    void writeFloatArray(float[] array) throws IOException;\n\n    void writeFloatArray(float[] array, int start, int n) throws IOException;\n\n    void writeIntArray(int[] array) throws IOException;\n\n    void writeIntArray(int[] array, int start, int n) throws IOException;\n\n    /**\n     * Write a string preceeded by its (int) length\n     */\n    void writeString(String string) throws IOException;\n\n    /**\n     * Write a string (no length is written)\n     */\n    void writeStringChars(String string) throws IOException;\n}\n"
  },
  {
    "path": "src/apmon/XDROutputStream.java",
    "content": "package apmon;\n\nimport java.io.DataOutputStream;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * A class for writing XDR files. Not too hard to do in Java since the XDR format is very\n * similar to the Java native DataStream format, except for String and the fact that elements\n * (ro an array of elements) are always padded to a multiple of 4 bytes.\n * <p>\n * This class requires the user to call the pad method, to skip to the next\n * 4-byte boundary after writing an element or array of elements that may not\n * span a multiple of 4 bytes.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n * @version $Id: XDROutputStream.java,v 1.1.1.1 2005-08-10 12:51:21 catac Exp $\n */\npublic class XDROutputStream extends DataOutputStream implements XDRDataOutput {\n    private final static byte[] padding = {0, 0, 0, 0};\n    private CountedOutputStream cout;\n\n    public XDROutputStream(OutputStream out) {\n        super(new CountedOutputStream(out));\n        cout = (CountedOutputStream) this.out;\n    }\n\n    public void writeString(String s) throws IOException {\n        writeInt(s.length());\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n\n    public void writeStringChars(String s) throws IOException {\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n\n    public void writeIntArray(int[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeInt(array[i]);\n    }\n\n    public void writeIntArray(int[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeInt(array[i]);\n    }\n\n    public void writeDoubleArray(double[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeDouble(array[i]);\n    }\n\n    public void writeDoubleArray(double[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeDouble(array[i]);\n    }\n\n    public void writeFloatArray(float[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeFloat(array[i]);\n    }\n\n    public void writeFloatArray(float[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeFloat(array[i]);\n    }\n\n    /**\n     * Skips appropriate amount to bring stream to 4-byte boundary.\n     */\n    public void pad() throws IOException {\n        int offset = (int) (getBytesWritten() % 4);\n        if (offset != 0) write(padding, 0, 4 - offset);\n    }\n\n    public long getBytesWritten() {\n        return cout.getBytesWritten();\n    }\n\n    private static final class CountedOutputStream extends FilterOutputStream {\n        private long count = 0;\n\n        CountedOutputStream(OutputStream out) {\n            super(out);\n        }\n\n        public void write(int b) throws IOException {\n            out.write(b);\n            count++;\n        }\n\n        public void write(byte[] data) throws IOException {\n            out.write(data);\n            count += data.length;\n        }\n\n        public void write(byte[] data, int off, int len) throws IOException {\n            out.write(data, off, len);\n            count += len;\n        }\n\n        public long getBytesWritten() {\n            return count;\n        }\n    }\n}\n"
  },
  {
    "path": "src/apmon/host/HostPropertiesMonitor.java",
    "content": "package apmon.host;\n\nimport java.util.HashMap;\nimport java.util.Hashtable;\n\npublic class HostPropertiesMonitor {\n\n    final static String osName = System.getProperty(\"os.name\");\n    static ProcReader reader = null;\n    static MacHostPropertiesMonitor macHostMonitor = null;\n\n    static {\n        if (System.getProperty(\"os.name\").indexOf(\"Linux\") == -1 && System.getProperty(\"os.name\").indexOf(\"Mac\") == -1) {\n            System.loadLibrary(\"system\");\n        } else if (System.getProperty(\"os.name\").indexOf(\"Linux\") != -1) {\n            reader = new ProcReader();\n        } else {\n            macHostMonitor = new MacHostPropertiesMonitor();\n        }\n    }\n\n    public HashMap getHashParams() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getHashedValues();\n        }\n\n        return null;\n    }\n\n    public native String getMacAddresses();\n\n    public String getMacAddressesCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getMacAddress();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getMacAddresses();\n        return getMacAddresses();\n    }\n\n    public native void update();\n\n    public void updateCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            reader.update();\n            return;\n        }\n        if (osName.indexOf(\"Mac\") != -1) {\n            macHostMonitor.update();\n            return;\n        }\n        update();\n    }\n\n    public native String getCpuUsage();\n\n    public String getCpuUsageCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getCPUUsage();\n        }\n        if (osName.indexOf(\"Mac\") != -1) {\n            return macHostMonitor.getCpuUsage();\n        }\n        return getCpuUsage();\n    }\n\n    public native String getCpuUSR();\n\n    public String getCpuUSRCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getCPUUsr();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getCpuUSR();\n        return getCpuUSR();\n    }\n\n    public native String getCpuSYS();\n\n    public String getCpuSYSCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getCPUSys();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getCpuSYS();\n        return getCpuSYS();\n    }\n\n    public native String getCpuNICE();\n\n    public String getCpuNICECall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getCPUNice();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getCpuNICE();\n        return getCpuNICE();\n    }\n\n    public native String getCpuIDLE();\n\n    public String getCpuIDLECall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getCPUIdle();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getCpuIDLE();\n        return getCpuIDLE();\n    }\n\n    public native String getPagesIn();\n\n    public String getPagesInCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getPagesIn();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getPagesIn();\n        return getPagesIn();\n    }\n\n    public native String getPagesOut();\n\n    public String getPagesOutCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getPagesOut();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getPagesOut();\n        return getPagesOut();\n    }\n\n    public native String getMemUsage();\n\n    public String getMemUsageCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getMemUsage();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getMemUsage();\n        return getMemUsage();\n    }\n\n    public native String getMemUsed();\n\n    public String getMemUsedCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getMemUsed();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getMemUsed();\n        return getMemUsed();\n    }\n\n\n    public String getMemTotalCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getMemTotal();\n        }\n        return null;\n    }\n\n\n    public String getSwapFreeCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getSwapFree();\n        }\n\n        return null;\n    }\n\n    public String getSwapTotalCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getSwapTotal();\n        }\n\n        return null;\n    }\n\n    public native String getMemFree();\n\n    public String getMemFreeCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getMemFree();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getMemFree();\n        return getMemFree();\n    }\n\n    public native String getDiskIO();\n\n    public String getDiskIOCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getDiskIO();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getDiskIO();\n        return getDiskIO();\n    }\n\n    public native String getDiskTotal();\n\n    public String getDiskTotalCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getDiskTotal();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getDiskTotal();\n        return getDiskTotal();\n    }\n\n    public native String getDiskUsed();\n\n    public String getDiskUsedCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getDiskUsed();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getDiskUsed();\n        return getDiskUsed();\n    }\n\n    public native String getDiskFree();\n\n    public String getDiskFreeCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getDiskFree();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getDiskFree();\n        return getDiskFree();\n    }\n\n    public native String getNoProcesses();\n\n    public String getNoProcessesCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getNoProcesses();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNoProcesses();\n        return getNoProcesses();\n    }\n\n    public native String getLoad1();\n\n    public String getLoad1Call() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getLoad1();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getLoad1();\n        return getLoad1();\n    }\n\n    public native String getLoad5();\n\n    public String getLoad5Call() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getLoad5();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getLoad5();\n        return getLoad5();\n    }\n\n    public native String getLoad15();\n\n    public String getLoad15Call() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getLoad15();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getLoad15();\n        return getLoad15();\n    }\n\n    public native String[] getNetInterfaces();\n\n    public String[] getNetInterfacesCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getNetInterfaces();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNetInterfaces();\n        return getNetInterfaces();\n    }\n\n    public native String getNetIn(String ifName);\n\n    public String getNetInCall(String ifName) {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getNetIn(ifName);\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNetIn(ifName);\n        return getNetIn(ifName);\n    }\n\n    public native String getNetOut(String ifName);\n\n    public String getNetOutCall(String ifName) {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getNetOut(ifName);\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNetOut(ifName);\n        return getNetOut(ifName);\n    }\n\n    public native Hashtable getProcessesState();\n\n    public Hashtable getPState() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getProcessesState();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getProcessesState();\n        return getProcessesState();\n    }\n\n    public native Hashtable getNetSockets();\n\n    public Hashtable getSockets() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getNetSockets();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNetSockets();\n        return getNetSockets();\n    }\n\n    public native Hashtable getTcpDetails();\n\n    public Hashtable getTCPDetails() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            return reader.getTcpDetails();\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getTcpDetails();\n        return getTcpDetails();\n    }\n\n    public void stopIt() {\n        reader.stopIt();\n    }\n\n} // end of class HostPropertiesMonitor\n\n"
  },
  {
    "path": "src/apmon/host/MacHostPropertiesMonitor.java",
    "content": "package apmon.host;\n\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.StringTokenizer;\n\n/**\n * @author Gregory Denis\n * <p>\n * TODO To change the template for this generated type comment go to Window -\n * Preferences - Java - Code Style - Code Templates\n */\npublic class MacHostPropertiesMonitor {\n\n    protected static Object lock = new Object();\n    protected static int ptnr = 0;\n    protected String[] networkInterfaces;\n    protected String activeInterface;\n    protected String cpuUsage = \"0\";\n    protected String cpuUSR = \"0\";\n    protected String cpuSYS = \"0\";\n    protected String cpuIDLE = \"0\";\n    protected String nbProcesses = \"0\";\n    protected String load1 = \"0\";\n    protected String load5 = \"0\";\n    protected String load15 = \"0\";\n    protected String memUsed = \"0\";\n    protected String memFree = \"0\";\n    protected String memUsage = \"0\";\n    protected String netIn = \"0\";\n    protected String netOut = \"0\";\n    protected String pagesIn = \"0\";\n    protected String pagesOut = \"0\";\n    protected String macAddress = \"unknown\";\n    protected String diskIO = \"0\";\n    protected String diskIn = \"0\";\n    protected String diskOut = \"0\";\n    protected String diskFree = \"0\";\n    protected String diskUsed = \"0\";\n    protected String diskTotal = \"0\";\n    protected String command = \"\";\n    protected cmdExec execute = null;\n    protected String sep = null;\n    protected Hashtable netSockets = null;\n    protected Hashtable netTcpDetails = null;\n    private Parser parser = null;\n\n    public MacHostPropertiesMonitor() {\n\n        parser = new Parser();\n        execute = new cmdExec();\n        execute.setTimeout(3 * 1000);\n        sep = System.getProperty(\"file.separator\");\n        // get the network interfaces up\n        command = sep + \"sbin\" + sep + \"ifconfig -l -u\";\n        String result = execute.executeCommand(command, \"lo0\");\n        //System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            System.out.println(command + \": No result???\");\n        } else {\n            int where = result.indexOf(\"lo0\");\n            networkInterfaces =\n                    result\n                            .substring(where + 3, result.length())\n                            .replaceAll(\"  \", \" \")\n                            .trim()\n                            .split(\n                                    \" \");\n\n            //\t\t\t get the currently used Mac Address\n            for (int i = 0; i < networkInterfaces.length; i++) {\n                String current = networkInterfaces[i];\n                command = sep + \"sbin\" + sep + \"ifconfig \" + current;\n                result = execute.executeCommand(command, current);\n                //System.out.println(command + \" = \" + result);\n                if (result == null || result.equals(\"\")) {\n                    System.out.println(command + \": No result???\");\n                } else {\n                    if (result.indexOf(\"inet \") != -1) {\n                        int pointI = result.indexOf(\"ether\");\n                        int pointJ = result.indexOf(\"media\", pointI);\n                        macAddress =\n                                result.substring(pointI + 5, pointJ).trim();\n                        //System.out.println(\"Mac Address:\" + macAddress);\n                        activeInterface = current;\n                    }\n                }\n            }\n        }\n\n        //\t\t get the disk information\n        command = sep + \"bin\" + sep + \"df -k -h \" + sep;\n        result = execute.executeCommand(command, \"/dev\");\n        //System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            System.out.println(command + \": No result???\");\n        } else {\n            parseDf(result);\n        }\n\n        update();\n    }\n\n    public String getMacAddresses() {\n        return macAddress;\n    }\n\n    public void update() {\n\n        if (execute == null) {\n            execute = new cmdExec();\n            execute.setTimeout(100 * 1000);\n        }\n\n        // get CPU, load, Mem, Pages, Processes from '/usr/bin/top'\n        command = sep + \"usr\" + sep + \"bin\" + sep\n                + \"top -d -l2 -n1 -F -R\";\n        String result = execute.executeCommand(command, \"PID\", 2);\n        //System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            System.out.println(\"No result???\");\n        } else {\n            parseTop(result);\n        }\n    }\n\n    private void parseIfConfig(String toParse) {\n\n        //System.out.println(\"result of ifconfig:\" + toParse);\n        if (toParse.indexOf(\"inet \") != -1) {\n            int pointI = toParse.indexOf(\"ether\");\n            int pointJ = toParse.indexOf(\"media\", pointI);\n            macAddress = toParse.substring(pointJ + 5, pointI).trim();\n            System.out.println(\"Mac Address:\" + macAddress);\n        }\n    }\n\n    private void parseDf(String toParse) {\n\n        //System.out.println(\"result of df -k -h /:\" + toParse);\n\n        int pointI = toParse.indexOf(\"/dev/\");\n        int pointJ = 0;\n        int pointK = 0;\n\n        // Get the size of the root disk\n        try {\n            pointJ = toParse.indexOf(\" \", pointI);\n            pointK = indexOfUnitLetter(toParse, pointJ);\n            diskTotal = toParse.substring(pointJ, pointK).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the capacity used\n        try {\n            pointI = toParse.indexOf(\" \", pointK);\n            pointJ = indexOfUnitLetter(toParse, pointI);\n            diskUsed = toParse.substring(pointI, pointJ).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the free space\n        try {\n            pointK = toParse.indexOf(\" \", pointJ);\n            pointI = indexOfUnitLetter(toParse, pointK);\n            diskFree = toParse.substring(pointK, pointI).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n\t\t/*System.out.println(\n            \"Disk: Total:\"\n\t\t\t\t+ diskTotal\n\t\t\t\t+ \" Used:\"\n\t\t\t\t+ diskUsed\n\t\t\t\t+ \" Free:\"\n\t\t\t\t+ diskFree);*/\n    }\n\n    private int indexOfUnitLetter(String inside, int from) {\n\n        int temp = inside.indexOf('K', from);\n        if (temp == -1 || (temp - from > 10)) {\n            temp = inside.indexOf('M', from);\n            if (temp == -1 || (temp - from > 10)) {\n                temp = inside.indexOf('G', from);\n                if (temp == -1 || (temp - from > 10)) {\n                    temp = inside.indexOf('B', from);\n                    if (temp == -1 || (temp - from > 10)) {\n                        temp = inside.indexOf('T', from);\n                        if (temp == -1 || (temp - from > 10)) {\n                            temp = inside.indexOf('b', from);\n                            if (temp - from > 10)\n                                temp = -1;\n                        }\n                    }\n                }\n            }\n        }\n        return temp;\n    }\n\n    private int lastIndexOfUnitLetter(String inside, int from) {\n\n        int temp = inside.lastIndexOf('K', from);\n        if (temp == -1 || (from - temp > 10)) {\n            temp = inside.lastIndexOf('M', from);\n            if (temp == -1 || (from - temp > 10)) {\n                temp = inside.lastIndexOf('G', from);\n                if (temp == -1 || (from - temp > 10)) {\n                    temp = inside.lastIndexOf('B', from);\n                    if (temp == -1 || (from - temp > 10)) {\n                        temp = inside.lastIndexOf('T', from);\n                        if (temp == -1 || (from - temp > 10)) {\n                            temp = inside.lastIndexOf('b', from);\n                            if (from - temp > 10)\n                                temp = -1;\n                        }\n                    }\n                }\n            }\n        }\n        return temp;\n    }\n\n    private double howMuchKiloBytes(char a) {\n\n        switch (a) {\n            case 'T':\n                return 1073741824.0;\n            case 'G':\n                return 1048576.0;\n            case 'M':\n                return 1024.0;\n            case 'K':\n                return 1.0;\n            case 'B':\n                return 0.0009765625;\n            default:\n                return 1.0;\n        }\n    }\n\n    private double howMuchMegaBytes(char a) {\n\n        switch (a) {\n            case 'T':\n                return 1048576.0;\n            case 'G':\n                return 1024.0;\n            case 'M':\n                return 1.0;\n            case 'K':\n                return 0.0009765625;\n            case 'B':\n                return 0.0000009537;\n            default:\n                return 1.0;\n        }\n    }\n\n    private void parseNetstat() {\n        String output = execute.executeCommandReality(\"netstat -an\", \"\");\n        if (output != null && !output.equals(\"\")) {\n            parser.parse(output);\n            String line = parser.nextLine();\n\n            netSockets.put(\"tcp\", new Integer(0));\n            netSockets.put(\"udp\", new Integer(0));\n            netSockets.put(\"unix\", new Integer(0));\n            netSockets.put(\"icm\", new Integer(0));\n\n            netTcpDetails.put(\"ESTABLISHED\", new Integer(0));\n            netTcpDetails.put(\"SYN_SENT\", new Integer(0));\n            netTcpDetails.put(\"SYN_RECV\", new Integer(0));\n            netTcpDetails.put(\"FIN_WAIT1\", new Integer(0));\n            netTcpDetails.put(\"FIN_WAIT2\", new Integer(0));\n            netTcpDetails.put(\"TIME_WAIT\", new Integer(0));\n            netTcpDetails.put(\"CLOSED\", new Integer(0));\n            netTcpDetails.put(\"CLOSE_WAIT\", new Integer(0));\n            netTcpDetails.put(\"LAST_ACK\", new Integer(0));\n            netTcpDetails.put(\"LISTEN\", new Integer(0));\n            netTcpDetails.put(\"CLOSING\", new Integer(0));\n            netTcpDetails.put(\"UNKNOWN\", new Integer(0));\n\n            try {\n                String key = null;\n                int value = 0;\n                while (line != null) {\n                    if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                        line = parser.nextLine();\n                        continue;\n                    }\n                    if (line.startsWith(\"tcp\")) {\n                        key = \"tcp\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                        StringTokenizer st = new StringTokenizer(line, \" []\");\n                        while (st.hasMoreTokens()) {\n                            String element = st.nextToken();\n                            key = element;\n                            if (netTcpDetails.containsKey(element)) {\n                                value = ((Integer) netTcpDetails.get(key)).intValue();\n                                value++;\n                                netTcpDetails.put(key, new Integer(value));\n                            }\n                        }\n                    }\n                    if (line.startsWith(\"udp\")) {\n                        key = \"udp\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    if (line.startsWith(\"unix\")) {\n                        key = \"unix\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    if (line.startsWith(\"icm\")) {\n                        key = \"icm\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    line = parser.nextLine();\n                }\n            } catch (Exception e) {\n            }\n        }\n    }\n\n    private void parseTop(String toParse) {\n\n        //System.out.println(\"\\n******\\n\"+toParse+\"\\n********\\n\");\n\n        int pointA = 0;\n        int pointB = 0;\n        int unitPos = 0;\n        double sum = 0.0;\n\n        //\t\t Get number of total Processes\n        try {\n            pointA = toParse.indexOf(\"Procs:\");\n            //System.out.println(\"First Procs at \" + pointA);\n            pointA = toParse.indexOf(\"Procs:\", pointA + 6) + 6;\n            //System.out.println(\"Second Procs at \" + pointA);\n            pointB = toParse.indexOf(\",\", pointA + 1);\n            nbProcesses = toParse.substring(pointA, pointB).trim();\n            //System.out.println(nbProcesses + \" processes\");\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the loads...\n        try {\n            pointA = toParse.indexOf(\"LoadAvg:\", pointA);\n            pointA += 9;\n            pointB = toParse.indexOf(\",\", pointA);\n            load1 = toParse.substring(pointA, pointB).trim();\n            pointA = toParse.indexOf(\",\", pointB + 1);\n            load5 = toParse.substring(pointB + 1, pointA).trim();\n            pointB = toParse.indexOf(\"CPU:\", pointA + 1);\n            pointB = toParse.lastIndexOf(\".\", pointB);\n            load15 = toParse.substring(pointA + 1, pointB).trim();\n            //System.out.println(\"load: [\" + load1 + \"][\" + load5 + \"][\" + load15 + \"]\");\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get CPUs...\n        try {\n            pointB = toParse.indexOf(\"CPU:\", pointB + 1) + 4;\n            pointA = toParse.indexOf(\"% user\", pointB);\n            cpuUSR = toParse.substring(pointB, pointA).trim();\n            pointA = toParse.indexOf(\",\", pointA);\n            pointB = toParse.indexOf(\"% sys\", pointA + 1);\n            cpuSYS = toParse.substring(pointA + 1, pointB).trim();\n            pointA = toParse.indexOf(\",\", pointB);\n            pointB = toParse.indexOf(\"% idle\", pointA + 1);\n            cpuIDLE = toParse.substring(pointA + 1, pointB).trim();\n            sum = 100.0 - Double.parseDouble(cpuIDLE);\n            cpuUsage = String.valueOf(sum);\n\t\t\t/*System.out.println(\"Cpu Usage:\" + cpuUsage + \" user:\"\n\t\t\t\t\t+ cpuUSR + \" sys:\" + cpuSYS\n\t\t\t\t\t+ \" idle:\" + cpuIDLE);*/\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        //\t\t Get Mem...\n        try {\n            pointA = toParse.indexOf(\"PhysMem\", pointB);\n            pointA += 8;\n            pointB = toParse.indexOf(\"M used\", pointA);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            memUsed = toParse.substring(pointA + 1, pointB).trim();\n            pointB = toParse.indexOf(\"M free\", pointB);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            memFree = toParse.substring(pointA + 1, pointB).trim();\n            //System.out.println(\"Mem Used:\"+memUsed+\"M Free:\"+memFree+\"M\");\n            sum = Double.parseDouble(memUsed) + Double.parseDouble(memFree);\n            double percentage = Integer.parseInt(memUsed) / sum * 100;\n            memUsage = String.valueOf(percentage);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Pages In/Out...\n        try {\n            pointA = toParse.indexOf(\"VirtMem:\", pointB + 6);\n            pointB = toParse.indexOf(\"pagein\", pointA);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            pagesIn = toParse.substring(pointA + 1, pointB).trim();\n            pointA = toParse.indexOf(\"pageout\", pointB);\n            pointB = toParse.lastIndexOf(\",\", pointA);\n            pagesOut = toParse.substring(pointB + 1, pointA).trim();\n            //System.out.println(\"Pages In:\" + pagesIn + \" Out\" + pagesOut);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n            System.out.println(\"Can't find pages in :\" + toParse);\n        }\n        ;\n\n        // Get Network IO...\n        try {\n            pointA = toParse.indexOf(\"Networks:\", pointB) + 9;\n            pointB = toParse.indexOf(\"data =\", pointA) + 6;\n            pointA = toParse.indexOf(\"in\", pointB);\n            unitPos = lastIndexOfUnitLetter(toParse, pointA);\n            netIn = toParse.substring(pointB, unitPos).trim();\n            //System.out.print(\"Net In:\" + netIn);\n            double factor =\n                    howMuchMegaBytes(\n                            (toParse.substring(unitPos, unitPos + 1).toCharArray())[0]);\n            netIn = String.valueOf(Double.parseDouble(netIn) * factor * 4);\n            pointB = toParse.indexOf(\"out\", pointA);\n            unitPos = lastIndexOfUnitLetter(toParse, pointB);\n            factor =\n                    howMuchMegaBytes(\n                            (toParse.substring(unitPos, unitPos + 1).toCharArray())[0]);\n            netOut = toParse.substring(pointA + 3, unitPos).trim();\n            //System.out.println(\"Net Out:\" + netOut);\n            netOut = String.valueOf(Double.parseDouble(netOut) * factor);\n            //System.out.println(\"Network In:\" + netIn + \" OUT:\" + netOut);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n            System.out.println(e);\n        }\n        ;\n\n        // Get Disks IO...\n        try {\n            pointB = toParse.indexOf(\"Disks:\", pointA) + 6;\n            pointA = toParse.indexOf(\"data =\", pointB) + 6;\n            pointB = toParse.indexOf(\"in,\", pointA);\n            unitPos = lastIndexOfUnitLetter(toParse, pointB);\n            diskIn = toParse.substring(pointA, unitPos).trim();\n            pointA = toParse.indexOf(\"out\", pointB);\n            unitPos = lastIndexOfUnitLetter(toParse, pointA);\n            diskOut = toParse.substring(pointB + 3, unitPos).trim();\n\n            //System.out.println(\"diskIO In:\" + diskIn + \" Out:\" + diskOut);\n            diskIO = diskOut;\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n    }\n\n    public Hashtable getProcessesState() {\n        Hashtable states = null;\n        String output = execute.executeCommandReality(\"ps -e -A -o state\", \"\");\n        if (output != null && !output.equals(\"\")) {\n\n            parser.parse(output);\n            String line = parser.nextLine();\n            int nr = 0;\n\n            states = new Hashtable();\n            states.put(\"D\", new Integer(0));\n            states.put(\"R\", new Integer(0));\n            states.put(\"S\", new Integer(0));\n            states.put(\"T\", new Integer(0));\n            states.put(\"Z\", new Integer(0));\n\n            while (line != null) {\n                if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                    line = parser.nextLine();\n                    continue;\n                }\n                Enumeration e = states.keys();\n                while (e.hasMoreElements()) {\n                    String key = (String) e.nextElement();\n                    if (line.startsWith(key)) {\n                        int x = ((Integer) states.get(key)).intValue();\n                        x++;\n                        states.put(key, new Integer(x));\n                    }\n                }\n                line = parser.nextLine();\n            }\n        }\n        return states;\n    }\n\n    public String getCpuUsage() {\n        return cpuUsage;\n    }\n\n    public String getCpuUSR() {\n        return cpuUSR;\n    }\n\n    public String getCpuSYS() {\n        return cpuSYS;\n    }\n\n    public String getCpuNICE() {\n        return \"0\";\n    }\n\n    public String getCpuIDLE() {\n        return cpuIDLE;\n    }\n\n    public String getPagesIn() {\n        return pagesIn;\n    }\n\n    public String getPagesOut() {\n        return pagesOut;\n    }\n\n    public String getMemUsage() {\n        return memUsage;\n    }\n\n    public String getMemUsed() {\n        return memUsed;\n    }\n\n    public String getMemFree() {\n        return memFree;\n    }\n\n    public String getDiskIO() {\n        return diskIO;\n    }\n\n    public String getDiskTotal() {\n        return diskTotal;\n    }\n\n    public String getDiskUsed() {\n        return diskUsed;\n    }\n\n    public String getDiskFree() {\n        return diskFree;\n    }\n\n    public String getNoProcesses() {\n        return nbProcesses;\n    }\n\n    public Hashtable getNetSockets() {\n        return netSockets;\n    }\n\n    public Hashtable getTcpDetails() {\n        return netTcpDetails;\n    }\n\n    public String getLoad1() {\n        return load1;\n    }\n\n    public String getLoad5() {\n        return load5;\n    }\n\n    public String getLoad15() {\n        return load15;\n    }\n\n    public String[] getNetInterfaces() {\n        return networkInterfaces;\n    }\n\n    public String getNetIn(String ifName) {\n        if (ifName.equalsIgnoreCase(activeInterface))\n            return netIn;\n        else\n            return \"0\";\n    }\n\n    public String getNetOut(String ifName) {\n        if (ifName.equalsIgnoreCase(activeInterface))\n            return netOut;\n        return \"0\";\n    }\n}\n"
  },
  {
    "path": "src/apmon/host/Parser.java",
    "content": "package apmon.host;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.util.StringTokenizer;\n\npublic class Parser {\n\n    private StringTokenizer st = null;\n\n    private StringTokenizer auxSt = null;\n\n    public Parser() {\n    }\n\n    public void parse(String text) {\n\n        st = new StringTokenizer(text);\n    }\n\n    public void parseAux(String text) {\n\n        auxSt = new StringTokenizer(text);\n    }\n\n    public void parseFromFile(String fileName) {\n\n        BufferedReader reader = null;\n        FileReader fr = null;\n\n        try {\n            fr = new FileReader(fileName);\n            reader = new BufferedReader(fr);\n            String str = \"\";\n            String line = \"\";\n            while ((line = reader.readLine()) != null)\n                str += line + \"\\n\";\n            st = new StringTokenizer(str);\n        } catch (Exception e) {\n            st = null;\n        } finally {\n            if (fr != null) {\n                try {\n                    fr.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            if (reader != null) {\n                try {\n                    reader.close();\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n    }\n\n    public String nextLine() {\n\n        if (st == null)\n            return null;\n        try {\n            return st.nextToken(\"\\n\");\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public String nextAuxLine() {\n\n        if (auxSt == null)\n            return null;\n        try {\n            return auxSt.nextToken(\"\\n\");\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public String nextToken() {\n\n        if (st == null)\n            return \"\";\n        try {\n            return st.nextToken();\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public boolean hasMoreTokens() {\n        return (st != null && st.hasMoreTokens());\n    }\n\n    public String nextToken(String token) {\n\n        if (st == null)\n            return \"\";\n        try {\n            return st.nextToken(token);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public boolean hasMoreAuxTokens() {\n        return (auxSt != null && auxSt.hasMoreTokens());\n    }\n\n    public String nextAuxToken() {\n\n        if (auxSt == null)\n            return \"\";\n        try {\n            return auxSt.nextToken();\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public String nextAuxToken(String token) {\n\n        if (auxSt == null)\n            return \"\";\n        try {\n            return auxSt.nextToken(token);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public String getTextAfterToken(String text, String start) {\n        if (text.indexOf(start) == -1)\n            return null;\n        return text.substring(text.indexOf(start) + start.length());\n    }\n\n    public String getTextBeforeToken(String text, String end) {\n        if (text.indexOf(end) == -1)\n            return text;\n        return text.substring(0, text.indexOf(end));\n    }\n\n    public String getTextBetween(String text, String start, String end) {\n        if (text.indexOf(start) == -1)\n            return null;\n        text = text.substring(text.indexOf(start) + start.length());\n        if (text.lastIndexOf(end) == -1)\n            return text;\n        return text.substring(0, text.lastIndexOf(end));\n    }\n\n    public String[] listFiles(String directory) {\n\n        String[] fileList = null;\n        try {\n            File dir = new File(directory);\n            if (!dir.isDirectory())\n                return null;\n            File[] list = dir.listFiles();\n            if (list == null)\n                return null;\n            fileList = new String[list.length];\n            for (int i = 0; i < list.length; i++)\n                fileList[i] = list[i].getName();\n        } catch (Exception e) {\n            return null;\n        }\n        return fileList;\n    }\n\n} // end of class Parser\n\n"
  },
  {
    "path": "src/apmon/host/ProcReader.java",
    "content": "package apmon.host;\n\nimport apmon.ApMonMonitoringConstants;\n\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.StringTokenizer;\n\n//import lisa.core.util.cmdExec;\n\n/**\n * Designated class that reads from the proc different parameter values.\n */\npublic class ProcReader {\n\n    static int cnt = 0;\n\n    private HashMap hm = null;\n\n    private cmdExec exec = null;\n\n    private Parser parser = null;\n\n    private String[] netInterfaces = null;\n\n    private String hwAddress = null;\n\n    private String cpuUsr = null;\n\n    private long dcpuUsr = 0;\n\n    private String cpuNice = null;\n\n    private long dcpuNice = 0;\n\n    private String cpuSys = null;\n\n    private long dcpuSys = 0;\n\n    private String cpuIdle = null;\n\n    private long dcpuIdle = 0;\n\n    private String cpuUsage = null;\n\n    private String pagesIn = null;\n\n    private long dpagesIn = 0;\n\n    private String pagesOut = null;\n\n    private long dpagesOut = 0;\n\n    private String memUsage = null;\n\n    private String memTotal = null;\n\n    private String memUsed = null;\n\n    private String memFree = null;\n\n    private String swapTotal = null;\n\n    private String swapFree = null;\n\n    private String swapUsed = null;\n\n    private String swapUsage = null;\n\n    private String diskIO = null;\n\n    private long ddiskIO = 0;\n\n    private long dblkRead = 0;\n\n    private long dblkWrite = 0;\n\n    private String diskTotal = null;\n\n    private String diskUsed = null;\n\n    private String diskFree = null;\n\n    private String diskUsage = null;\n\n    private String processesNo = null;\n\n    private String load1 = null;\n\n    private String load5 = null;\n\n    private String load15 = null;\n\n    private Hashtable netIn = null;\n\n    private Hashtable dnetIn = null;\n\n    private Hashtable netOut = null;\n\n    private Hashtable dnetOut = null;\n\n    private Hashtable states = null;\n\n    private Hashtable netSockets = null;\n\n    private Hashtable netTcpDetails = null;\n\n    private long lastCall = 0;\n\n    public ProcReader() {\n        netIn = new Hashtable();\n        dnetIn = new Hashtable();\n        netOut = new Hashtable();\n        dnetOut = new Hashtable();\n        exec = new cmdExec();\n        parser = new Parser();\n        states = new Hashtable();\n        netSockets = new Hashtable();\n        netTcpDetails = new Hashtable();\n\n        update();\n    }\n\n    public static void main(String[] args) {\n\n        ProcReader reader = new ProcReader();\n        while (true) {\n            reader.update();\n            System.out.println(\"\");\n            System.out.println(\"CPU Sys: \" + reader.getCPUSys());\n            System.out.println(\"CPU Usr: \" + reader.getCPUUsr());\n            System.out.println(\"CPU Nice: \" + reader.getCPUNice());\n            System.out.println(\"CPU Idle: \" + reader.getCPUIdle());\n            System.out.println(\"CPU Usage: \" + reader.getCPUUsage());\n            System.out.println(\"\");\n            System.out.println(\"Pages in: \" + reader.getPagesIn());\n            System.out.println(\"Pages out: \" + reader.getPagesOut());\n            System.out.println(\"\");\n            System.out.println(\"Mem usage: \" + reader.getMemUsage());\n            System.out.println(\"Mem used: \" + reader.getMemUsed());\n            System.out.println(\"Mem free: \" + reader.getMemFree());\n            System.out.println(\"\");\n            System.out.println(\"Disk total: \" + reader.getDiskTotal());\n            System.out.println(\"Disk used: \" + reader.getDiskUsed());\n            System.out.println(\"Disk free: \" + reader.getDiskFree());\n            System.out.println(\"Disk usage: \" + reader.getDiskUsage());\n            System.out.println(\"Disk IO: \" + reader.getDiskIO());\n            System.out.println(\"\");\n            System.out.println(\"Processes: \" + reader.getNoProcesses());\n            System.out.println(\"Load1: \" + reader.getLoad1());\n            System.out.println(\"Load5: \" + reader.getLoad5());\n            System.out.println(\"Load15: \" + reader.getLoad15());\n            System.out.println(\"\");\n            System.out.println(\"MAC: \" + reader.getMacAddress());\n            System.out.println(\"Net IFS\");\n            String netIfs[] = reader.getNetInterfaces();\n            if (netIfs != null) {\n                for (int i = 0; i < netIfs.length; i++)\n                    System.out.print(netIfs[i] + \" \");\n                System.out.println(\"\");\n                System.out.println(\"Net in\");\n                for (int i = 0; i < netIfs.length; i++)\n                    System.out.print(reader.getNetIn(netIfs[i]) + \" \");\n                System.out.println(\"\");\n                System.out.println(\"Net out\");\n                for (int i = 0; i < netIfs.length; i++)\n                    System.out.print(reader.getNetOut(netIfs[i]) + \" \");\n                System.out.println(\"\");\n            }\n            System.out.println(\"\");\n            try {\n                Thread.sleep(1000);\n            } catch (Exception e) {\n            }\n        }\n    }\n\n    private void addNetInterface(String netInterface) {\n\n        if (netInterface == null || netInterface.equals(\"\")) return;\n        netInterface = netInterface.trim();\n        if (netInterfaces == null) {\n            netInterfaces = new String[1];\n            netInterfaces[0] = netInterface;\n            return;\n        }\n        for (int i = 0; i < netInterfaces.length; i++)\n            if (netInterface.equals(netInterfaces[i])) return;\n        String[] tmpNetInterfaces = new String[netInterfaces.length + 1];\n        System.arraycopy(netInterfaces, 0, tmpNetInterfaces, 0, netInterfaces.length);\n        tmpNetInterfaces[netInterfaces.length] = netInterface;\n        netInterfaces = tmpNetInterfaces;\n    }\n\n    public synchronized void update() {\n\n        cnt++;\n\n        long newCall = System.currentTimeMillis();\n        double diffCall = (newCall - lastCall) / 1000.0; // in seconds\n\n        String str = null;\n        String output = \"\";\n        String line = \"\";\n\n        if (hwAddress == null) {\n            output = exec.executeCommandReality(\"ifconfig -a\", \"b\");\n            if (exec.isError()) output = null;\n\n            if (output != null && !output.equals(\"\")) {\n                netInterfaces = null;\n                parser.parse(output);\n                line = parser.nextLine();\n                hwAddress = null;\n                while (line != null) {\n                    if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                        line = parser.nextLine();\n                        continue;\n                    }\n                    if (line == null) break;\n                    parser.parseAux(line);\n                    // get the name\n                    String netName = parser.nextAuxToken(\" \\t\\n\");\n                    if (netName != null && !netName.equals(\"\")) {\n                        addNetInterface(netName);\n                    }\n                    // get the hw address\n                    // str = parser.nextAuxToken(\"HWaddr\");\n                    str = parser.getTextAfterToken(line, \"HWaddr \");\n                    if (str != null) {\n                        hwAddress = str;\n                    }\n                    line = parser.nextLine();\n                }\n            }\n        }\n\n        pagesIn = pagesOut = null;\n        cpuUsage = cpuUsr = cpuIdle = cpuNice = cpuSys = diskIO = null;\n        parser.parseFromFile(\"/proc/stat\");\n        line = parser.nextLine();\n        while (line != null) {\n            if (line.startsWith(\"page\")) {\n                line = parser.getTextAfterToken(line, \"page \");\n                parser.parseAux(line);\n                pagesIn = parser.nextAuxToken();\n                pagesOut = parser.nextAuxToken();\n                long dpIn = 0, dpOut = 0;\n                try {\n                    dpIn = Long.parseLong(pagesIn);\n                } catch (Exception e) {\n                    dpIn = -1;\n                }\n                try {\n                    dpOut = Long.parseLong(pagesOut);\n                } catch (Exception e) {\n                    dpOut = -1;\n                }\n                if (dpIn >= 0) {\n                    pagesIn = \"\" + ((diffWithOverflowCheck(dpIn, dpagesIn)) / diffCall);\n                    dpagesIn = dpIn;\n                }\n                if (dpOut >= 0) {\n                    pagesOut = \"\" + ((diffWithOverflowCheck(dpOut, dpagesOut)) / diffCall);\n                    dpagesOut = dpOut;\n                }\n            }\n            if (line.startsWith(\"cpu\") && cpuUsr == null) {\n                line = parser.getTextAfterToken(line, \"cpu \");\n                parser.parseAux(line);\n                long dcUsr = 0, dcSys = 0, dcNice = 0, dcIdle = 0;\n                line = parser.nextAuxToken(); // cpu usr\n                try {\n                    dcUsr = Long.parseLong(line);\n\n                } catch (Exception e) {\n                    dcUsr = -1;\n                }\n                line = parser.nextAuxToken(); // cpu nice\n                try {\n                    dcNice = Long.parseLong(line);\n                } catch (Exception e) {\n                    dcNice = -1;\n                }\n                line = parser.nextAuxToken(); // cpu sys\n                try {\n                    dcSys = Long.parseLong(line);\n                } catch (Exception e) {\n                    dcSys = -1;\n                }\n                line = parser.nextAuxToken(); // cpu idle\n                try {\n                    dcIdle = Long.parseLong(line);\n                } catch (Exception e) {\n                    dcIdle = -1;\n                }\n\n                double tmpUsr = diffWithOverflowCheck(dcUsr, dcpuUsr) / diffCall;\n                double tmpSys = (diffWithOverflowCheck(dcSys, dcpuSys)) / diffCall;\n                double tmpIdle = (diffWithOverflowCheck(dcIdle, dcpuIdle)) / diffCall;\n                double tmpNice = (diffWithOverflowCheck(dcNice, dcpuNice)) / diffCall;\n                if (tmpUsr >= 0.0 && tmpSys >= 0.0 && tmpIdle >= 0.0 && tmpNice >= 0.0) {\n                    dcpuUsr = dcUsr;\n                    dcpuSys = dcSys;\n                    dcpuNice = dcNice;\n                    dcpuIdle = dcIdle;\n                    double dcTotalP = tmpUsr + tmpSys + tmpNice;\n                    double dcTotal = dcTotalP + tmpIdle;\n                    cpuUsr = \"\" + (100.0 * tmpUsr / dcTotal);\n                    cpuSys = \"\" + (100.0 * tmpSys / dcTotal);\n                    cpuNice = \"\" + (100.0 * tmpNice / dcTotal);\n                    cpuIdle = \"\" + (100.0 * tmpIdle / dcTotal);\n                    cpuUsage = \"\" + (100.0 * dcTotalP / dcTotal);\n                }\n            }\n            line = parser.nextLine();\n        }\n\n        output = exec.executeCommandReality(System.getProperty(\"user.home\") + \"/iostat -k\", \"L\");\n        if (exec.isError()) output = null;\n        if (output != null && !output.equals(\"\")) {\n            parser.parse(output);\n            line = parser.nextLine();\n            while (line != null && line.indexOf(\"avg-cpu\") == -1)\n                line = parser.nextLine();\n            if (line != null && cpuUsr == null) {\n                str = parser.nextToken(\" \\t\\n\");\n                if (str != null) cpuUsr = str;\n                str = parser.nextToken(\" \\t\\n\");\n                if (str != null) cpuNice = str;\n                str = parser.nextToken(\" \\t\\n\");\n                if (str != null) cpuSys = str;\n                str = parser.nextToken(\" \\t\\n\");\n                str = parser.nextToken(\" \\t\\n\");\n                if (str != null) cpuIdle = str;\n                double dcUsr = 0.0, dcSys = 0.0, dcNice = 0.0, dcIdle = 0.0, d = -1.0;\n                try {\n                    d = Double.parseDouble(cpuUsr);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dcUsr = d;\n                try {\n                    d = Double.parseDouble(cpuSys);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dcSys = d;\n                try {\n                    d = Double.parseDouble(cpuIdle);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dcIdle = d;\n                try {\n                    d = Double.parseDouble(cpuNice);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dcNice = d;\n                if ((dcUsr + dcSys + dcNice + dcIdle) != 0.0) cpuUsage = \"\" + (dcUsr + dcSys + dcNice);\n                str = parser.nextToken(\" \\t\\n\");\n                while (str != null && str.indexOf(\"Device:\") == -1)\n                    str = parser.nextToken(\" \\t\\n\");\n                if (str != null) {\n                    for (int i = 0; i < 5 && str != null; i++)\n                        str = parser.nextToken(\" \\t\\n\");\n                    long blkRead = 0, blkWrite = 0;\n                    while (true) {\n                        str = parser.nextToken(\" \\t\\n\");\n                        if (str == null) break;\n                        str = parser.nextToken(\" \\t\\n\"); // skip tps\n                        str = parser.nextToken(\" \\t\\n\"); // skip KB read /\n                        // sec\n                        str = parser.nextToken(\" \\t\\n\"); // skip KB write /\n                        // sec\n                        str = parser.nextToken(\" \\t\\n\"); // blk read / sec\n                        long l = 0;\n                        try {\n                            l = Long.parseLong(str);\n                        } catch (Exception e) {\n                            l = -1;\n                        }\n                        if (l >= 0) blkRead += l;\n                        str = parser.nextToken(\" \\t\\n\"); // blk written / sec\n                        l = 0;\n                        try {\n                            l = Long.parseLong(str);\n                        } catch (Exception e) {\n                            l = -1;\n                        }\n                        if (l >= 0.0) blkWrite += l;\n                    }\n\n                    double dRead = (diffWithOverflowCheck(blkRead, dblkRead)) / diffCall;\n                    double dWrite = (diffWithOverflowCheck(blkWrite, dblkWrite)) / diffCall;\n                    diskIO = \"\" + (dRead + dWrite);\n                    //ddiskIO = blkRead + blkWrite;\n                    dblkRead = blkRead;\n                    dblkWrite = blkWrite;\n                }\n            } else if (line != null) {\n                str = parser.nextToken(\" \\t\\n\");\n                while (str != null && str.indexOf(\"Device:\") == -1)\n                    str = parser.nextToken(\" \\t\\n\");\n                if (str != null) {\n                    for (int i = 0; i < 5 && str != null; i++)\n                        str = parser.nextToken(\" \\t\\n\");\n                    long blkRead = 0, blkWrite = 0;\n                    while (true) {\n                        str = parser.nextToken(\" \\t\\n\");\n                        if (str == null) break;\n                        str = parser.nextToken(\" \\t\\n\"); // skip tps\n                        str = parser.nextToken(\" \\t\\n\"); // skip KB read /\n                        // sec\n                        str = parser.nextToken(\" \\t\\n\"); // skip KB write /\n                        // sec\n                        str = parser.nextToken(\" \\t\\n\"); // blk read / sec\n                        long l = 0;\n                        try {\n                            l = Long.parseLong(str);\n                        } catch (Exception e) {\n                            l = -1;\n                        }\n                        if (l >= 0) blkRead += l;\n                        str = parser.nextToken(\" \\t\\n\"); // blk written / sec\n                        l = 0;\n                        try {\n                            l = Long.parseLong(str);\n                        } catch (Exception e) {\n                            l = -1;\n                        }\n                        if (l >= 0) blkWrite += l;\n                    }\n                    double dRead = (diffWithOverflowCheck(blkRead, dblkRead)) / diffCall;\n                    double dWrite = (diffWithOverflowCheck(blkWrite, dblkWrite)) / diffCall;\n                    diskIO = \"\" + (dRead + dWrite);\n                    ddiskIO = blkRead + blkWrite;\n\n                    dblkRead = blkRead;\n                    dblkWrite = blkWrite;\n                }\n            }\n        }\n\n        swapFree = swapTotal = memUsage = memFree = memUsed = null;\n        parser.parseFromFile(\"/proc/meminfo\");\n        line = parser.nextLine();\n        double dmemTotal = 0.0, dmemFree = 0.0;\n        while (line != null) {\n            if (line.startsWith(\"MemTotal\")) {\n                line = parser.getTextAfterToken(line, \"MemTotal:\");\n                parser.parseAux(line);\n                memTotal = parser.nextAuxToken();\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(memTotal);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dmemTotal = d;\n            } else if (line.startsWith(\"MemFree\")) {\n                line = parser.getTextAfterToken(line, \"MemFree:\");\n                parser.parseAux(line);\n                memFree = parser.nextAuxToken();\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(memFree);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0) dmemFree = d;\n            } else if (line.startsWith(\"SwapTotal\")) {\n                line = parser.getTextAfterToken(line, \"SwapTotal:\");\n                parser.parseAux(line);\n                swapTotal = parser.nextAuxToken();\n            } else if (line.startsWith(\"SwapFree\")) {\n                line = parser.getTextAfterToken(line, \"SwapFree:\");\n                parser.parseAux(line);\n                swapFree = parser.nextAuxToken();\n            }\n\n\n            line = parser.nextLine();\n        }\n\n        double dst = Double.valueOf(swapTotal).doubleValue();\n        double dsf = Double.valueOf(swapFree).doubleValue();\n        double dsu = dst - dsf;\n\n        swapUsed = \"\" + dsu;\n        swapUsage = \"\" + (1.0 - dsu / dst) * 100;\n\n        memFree = \"\" + (dmemFree / 1024.0);\n        memUsed = \"\" + ((dmemTotal - dmemFree) / 1024.0);\n        memUsage = \"\" + (100.0 * (dmemTotal - dmemFree) / dmemTotal);\n\n        output = exec.executeCommandReality(\"df -B 1024\", \"o\");\n        if (exec.isError()) output = null;\n        double size = 0.0, used = 0.0, available = 0.0, usage = 0.0;\n        if (output != null && output != \"\") {\n            parser.parse(output);\n            line = parser.nextToken(\" \\t\\n\");\n            int nr = 0;\n            for (int i = 0; i < 6 && line != null; i++)\n                line = parser.nextToken(\" \\t\\n\");\n            while (true) {\n                line = parser.nextToken(\" \\t\\n\");\n                if (line == null) break;\n                line = parser.nextToken(\" \\t\\n\"); // size\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0) break;\n                size += d;\n                line = parser.nextToken(\" \\t\\n\"); // used\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0) break;\n                used += d;\n                line = parser.nextToken(\" \\t\\n\"); // available\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0) break;\n                available += d;\n                line = parser.nextToken(\" \\t\\n\"); // usage\n                line = parser.getTextBeforeToken(line, \"%\");\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0) break;\n                usage += d;\n                nr++;\n                line = parser.nextToken(\" \\t\\n\");\n                if (line == null) break;\n            }\n            diskTotal = \"\" + (size / (1024.0 * 1024.0)); // total size (GB)\n            diskUsed = \"\" + (used / (1024.0 * 1024.0)); // used size (GB)\n            diskFree = \"\" + (available / (1024.0 * 1024.0)); // free size\n            // (GB)\n            diskUsage = \"\" + (usage * 1.0 / nr); // usage (%)\n        } else { // read from /proc/ide\n            String files[] = parser.listFiles(\"/proc/ide\");\n            if (files != null && files.length != 0) for (int i = 0; i < files.length; i++)\n                if (files[i].startsWith(\"hd\")) {\n                    parser.parseFromFile(\"/proc/ide/\" + files[i] + \"/capacity\");\n                    line = parser.nextLine();\n                    double d = 0.0;\n                    try {\n                        d = Double.parseDouble(line);\n                    } catch (Exception e) {\n                        d = -1.0;\n                    }\n                    if (d >= 0.0) size += d;\n                }\n            diskTotal = \"\" + (size / (1024.0 * 1024.0)); // disk total (GB)\n            diskFree = diskTotal;\n        }\n\n        /**\n         * old version\n         *\n         String[] files = parser.listFiles(\"/proc\");\n         processesNo = null;\n         if (files != null && files.length != 0) {\n         int nr = 0;\n         for (int i = 0; i < files.length; i++) {\n         char[] chars = files[i].toCharArray();\n         boolean isProc = true;\n         for (int j = 0; j < chars.length; j++)\n         if (!Character.isDigit(chars[j])) {\n         isProc = false;\n         break;\n         }\n         if (isProc) nr++;\n         }\n         processesNo = \"\" + nr;\n         }\n         */\n\n        /**\n         * new version\n         */\n        output = exec.executeCommandReality(\"ps -e -A -o state\", \"\");\n        if (output != null && !output.equals(\"\")) {\n            parser.parse(output);\n            line = parser.nextLine();\n            processesNo = null;\n            int pNo = 0;\n\n            states.put(\"D\", new Integer(0));\n            states.put(\"R\", new Integer(0));\n            states.put(\"S\", new Integer(0));\n            states.put(\"T\", new Integer(0));\n            states.put(\"Z\", new Integer(0));\n\n            while (line != null) {\n                if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                    line = parser.nextLine();\n                    continue;\n                }\n                Enumeration e = states.keys();\n                while (e.hasMoreElements()) {\n                    String key = (String) e.nextElement();\n                    if (line.startsWith(key)) {\n                        int value = ((Integer) states.get(key)).intValue();\n                        value++;\n                        pNo++;\n                        states.put(key, new Integer(value));\n                    }\n                }\n                line = parser.nextLine();\n            }\n            processesNo = \"\" + pNo;\n        }\n\n        /**\n         * run netstat\n         */\n        output = exec.executeCommandReality(\"netstat -an\", \"\");\n        if (output != null && !output.equals(\"\")) {\n            parser.parse(output);\n            line = parser.nextLine();\n\n            netSockets.put(\"tcp\", new Integer(0));\n            netSockets.put(\"udp\", new Integer(0));\n            netSockets.put(\"unix\", new Integer(0));\n            netSockets.put(\"icm\", new Integer(0));\n\n            netTcpDetails.put(\"ESTABLISHED\", new Integer(0));\n            netTcpDetails.put(\"SYN_SENT\", new Integer(0));\n            netTcpDetails.put(\"SYN_RECV\", new Integer(0));\n            netTcpDetails.put(\"FIN_WAIT1\", new Integer(0));\n            netTcpDetails.put(\"FIN_WAIT2\", new Integer(0));\n            netTcpDetails.put(\"TIME_WAIT\", new Integer(0));\n            netTcpDetails.put(\"CLOSED\", new Integer(0));\n            netTcpDetails.put(\"CLOSE_WAIT\", new Integer(0));\n            netTcpDetails.put(\"LAST_ACK\", new Integer(0));\n            netTcpDetails.put(\"LISTEN\", new Integer(0));\n            netTcpDetails.put(\"CLOSING\", new Integer(0));\n            netTcpDetails.put(\"UNKNOWN\", new Integer(0));\n\n            try {\n                String key = null;\n                int value = 0;\n                while (line != null) {\n                    if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                        line = parser.nextLine();\n                        continue;\n                    }\n                    if (line.startsWith(\"tcp\")) {\n                        key = \"tcp\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                        StringTokenizer st = new StringTokenizer(line, \" []\");\n                        while (st.hasMoreTokens()) {\n                            String element = st.nextToken();\n                            key = element;\n                            if (netTcpDetails.containsKey(element)) {\n                                value = ((Integer) netTcpDetails.get(key)).intValue();\n                                value++;\n                                netTcpDetails.put(key, new Integer(value));\n                            }\n                        }\n                    }\n                    if (line.startsWith(\"udp\")) {\n                        key = \"udp\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    if (line.startsWith(\"unix\")) {\n                        key = \"unix\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    if (line.startsWith(\"icm\")) {\n                        key = \"icm\";\n                        value = ((Integer) netSockets.get(key)).intValue();\n                        value++;\n                        netSockets.put(key, new Integer(value));\n                    }\n                    line = parser.nextLine();\n                }\n            } catch (Exception e) {\n            }\n        }\n\n\n        parser.parseFromFile(\"/proc/loadavg\");\n        load1 = load5 = load15 = null;\n        line = parser.nextToken(\" \\t\\n\"); // load1\n        if (line != null) {\n            double d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0) load1 = \"\" + d;\n            line = parser.nextToken(\" \\t\\n\"); // load5\n            d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0) load5 = \"\" + d;\n            line = parser.nextToken(\" \\t\\n\"); // load15\n            d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0) load15 = \"\" + d;\n        }\n\n        parser.parseFromFile(\"/proc/net/dev\");\n        if (netInterfaces == null) {\n            while (true) {\n                line = parser.nextToken(\":\\n\\t \");\n                if (line == null) break;\n                if (line.startsWith(\"eth\") || line.startsWith(\"lo\")) {\n                    addNetInterface(line);\n                    String name = line;\n                    line = parser.nextToken(\" \\t\\n\"); // bytes received\n                    long d = 0;\n                    long oldReceived = 0;\n                    if (dnetIn.containsKey(name)) {\n                        try {\n                            oldReceived = ((Long) dnetIn.get(name)).longValue();\n                        } catch (Exception e) {\n                            oldReceived = -1;\n                        }\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (oldReceived >= 0 && d >= 0) {\n                            double in = (diffWithOverflowCheck(d, oldReceived)) / diffCall;\n                            //double in = (d - oldReceived) / diffCall;\n                            in = in / (1024.0 * 1024.0);\n                            oldReceived = d;\n                            netIn.put(name, \"\" + in);\n                            dnetIn.put(name, new Long(oldReceived));\n                        }\n                    } else {\n                        d = 0;\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (d >= 0) {\n                            netIn.put(name, \"\" + d);\n                            dnetIn.put(name, new Long(d));\n                        }\n                    }\n                    line = parser.nextToken(\" \\t\\n\"); // packets received\n                    for (int i = 0; i < 6; i++)\n                        line = parser.nextToken(\" \\t\\n\");\n                    line = parser.nextToken(\" \\t\\n\"); // bytes sent\n                    d = 0;\n                    long oldSent = 0;\n                    if (dnetOut.containsKey(name)) {\n                        try {\n                            oldSent = ((Long) dnetOut.get(name)).longValue();\n                        } catch (Exception e) {\n                            oldSent = -1;\n                        }\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (oldSent >= 0 && d >= 0) {\n                            double out = (diffWithOverflowCheck(d, oldSent)) / diffCall;\n                            //double out = (d - oldSent) / diffCall;\n                            out = out / (1024.0 * 1024.0);\n                            oldSent = d;\n                            netOut.put(name, \"\" + out);\n                            dnetOut.put(name, new Long(oldSent));\n                        }\n                    } else {\n                        d = 0;\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (d >= 0) {\n                            netOut.put(name, \"\" + d);\n                            dnetOut.put(name, new Long(d));\n                        }\n                    }\n                    line = parser.nextToken(\" \\t\\n\"); // packets sent\n                }\n            }\n        } else {\n            while (true) {\n                line = parser.nextToken(\":\\n\\t \");\n                if (line == null) break;\n                boolean found = false;\n                for (int i = 0; i < netInterfaces.length; i++)\n                    if (line.equals(netInterfaces[i])) {\n                        found = true;\n                        break;\n                    }\n                if (found) {\n                    String name = line;\n                    line = parser.nextToken(\" \\t\\n:\"); // bytes received\n                    long d = 0;\n                    long oldReceived = 0;\n                    if (dnetIn.containsKey(name)) {\n                        try {\n                            oldReceived = ((Long) dnetIn.get(name)).longValue();\n                        } catch (Exception e) {\n                            oldReceived = -1;\n                        }\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (oldReceived >= 0 && d >= 0) {\n                            double in = (diffWithOverflowCheck(d, oldReceived)) / diffCall;\n                            //double in = (d - oldReceived) / diffCall;\n                            in = in / (1024.0 * 1024.0);\n                            oldReceived = d;\n                            netIn.put(name, \"\" + in);\n                            dnetIn.put(name, new Long(oldReceived));\n                        }\n                    } else {\n                        d = 0;\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (d >= 0) {\n                            netIn.put(name, \"\" + d);\n                            dnetIn.put(name, new Long(d));\n                        }\n                    }\n                    line = parser.nextToken(\" \\t\\n\"); // packets received\n                    for (int i = 0; i < 6; i++)\n                        line = parser.nextToken(\" \\t\\n\");\n                    line = parser.nextToken(\" \\t\\n\"); // bytes sent\n                    d = 0;\n                    long oldSent = 0;\n                    if (dnetOut.containsKey(name)) {\n                        try {\n                            oldSent = ((Long) dnetOut.get(name)).longValue();\n                        } catch (Exception e) {\n                            oldSent = -1;\n                        }\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n\n                        if (oldSent >= 0 && d >= 0) {\n                            double out = (diffWithOverflowCheck(d, oldSent)) / diffCall;\n                            //double out = (d - oldSent) / diffCall;\n                            out = out / (1024.0 * 1024.0);\n                            oldSent = d;\n                            netOut.put(name, \"\" + out);\n                            dnetOut.put(name, new Long(oldSent));\n                        }\n                    } else {\n                        d = 0;\n                        try {\n                            d = Long.parseLong(line);\n                        } catch (Exception e) {\n                            d = -1;\n                        }\n                        if (d >= 0) {\n                            netOut.put(name, \"\" + d);\n                            dnetOut.put(name, new Long(d));\n                        }\n                    }\n                    line = parser.nextToken(\" \\t\\n\"); // packets sent\n                }\n            }\n        }\n\n        //add all monitored info to a hashmap for serial processing\n        hm = new HashMap();\n        hm.put(ApMonMonitoringConstants.LSYS_LOAD1, load1);\n        hm.put(ApMonMonitoringConstants.LSYS_LOAD5, load5);\n        hm.put(ApMonMonitoringConstants.LSYS_LOAD15, load15);\n\n        hm.put(ApMonMonitoringConstants.LSYS_CPU_USR, cpuUsr);\n        hm.put(ApMonMonitoringConstants.LSYS_CPU_NICE, cpuNice);\n        hm.put(ApMonMonitoringConstants.LSYS_CPU_SYS, cpuSys);\n        hm.put(ApMonMonitoringConstants.LSYS_CPU_IDLE, cpuIdle);\n        hm.put(ApMonMonitoringConstants.LSYS_CPU_USAGE, cpuUsage);\n\n        hm.put(ApMonMonitoringConstants.LSYS_MEM_FREE, memFree);\n        hm.put(ApMonMonitoringConstants.LSYS_MEM_USED, memUsed);\n        hm.put(ApMonMonitoringConstants.LSYS_MEM_USAGE, memUsage);\n\n        hm.put(ApMonMonitoringConstants.LSYS_PAGES_IN, pagesIn);\n        hm.put(ApMonMonitoringConstants.LSYS_PAGES_OUT, pagesOut);\n\n        hm.put(ApMonMonitoringConstants.LSYS_SWAP_FREE, swapFree);\n        hm.put(ApMonMonitoringConstants.LSYS_SWAP_USED, swapUsed);\n        hm.put(ApMonMonitoringConstants.LSYS_SWAP_USAGE, swapUsage);\n\n        hm.put(ApMonMonitoringConstants.LSYS_PROCESSES, processesNo);\n\n        lastCall = newCall;\n    }\n\n    public synchronized HashMap getHashedValues() {\n        return hm;\n    }\n\n    public synchronized String getMacAddress() {\n\n        if (hwAddress != null) hwAddress = hwAddress.trim();\n        return hwAddress;\n    }\n\n    public synchronized String getCPUUsage() {\n\n        if (cpuUsage != null) cpuUsage = cpuUsage.trim();\n        return cpuUsage;\n    }\n\n    public synchronized String getCPUUsr() {\n\n        if (cpuUsr != null) cpuUsr = cpuUsr.trim();\n        return cpuUsr;\n    }\n\n    public synchronized String getCPUSys() {\n\n        if (cpuSys != null) cpuSys = cpuSys.trim();\n        return cpuSys;\n    }\n\n    public synchronized String getCPUNice() {\n\n        if (cpuNice != null) cpuNice = cpuNice.trim();\n        return cpuNice;\n    }\n\n    public synchronized String getCPUIdle() {\n\n        if (cpuIdle != null) cpuIdle = cpuIdle.trim();\n        return cpuIdle;\n    }\n\n    public synchronized String getPagesIn() {\n\n        if (pagesIn != null) pagesIn = pagesIn.trim();\n        return pagesIn;\n    }\n\n    public synchronized String getPagesOut() {\n\n        if (pagesOut != null) pagesOut = pagesOut.trim();\n        return pagesOut;\n    }\n\n    public synchronized String getMemUsage() {\n\n        if (memUsage != null) memUsage = memUsage.trim();\n        return memUsage;\n    }\n\n    public synchronized String getMemTotal() {\n\n        if (memTotal != null) memTotal = memTotal.trim();\n        return memTotal;\n    }\n\n    public synchronized String getMemUsed() {\n\n        if (memUsed != null) memUsed = memUsed.trim();\n        return memUsed;\n    }\n\n    public synchronized String getMemFree() {\n\n        if (memFree != null) memFree = memFree.trim();\n        return memFree;\n    }\n\n    public synchronized String getSwapTotal() {\n\n        if (swapTotal != null) swapTotal = swapTotal.trim();\n        return swapTotal;\n    }\n\n    public synchronized String getSwapFree() {\n\n        if (swapTotal != null) swapTotal = swapTotal.trim();\n        return swapTotal;\n    }\n\n    public synchronized String getDiskIO() {\n\n        if (diskIO != null) diskIO = diskIO.trim();\n        return diskIO;\n    }\n\n    public synchronized String getDiskTotal() {\n\n        if (diskTotal != null) diskTotal = diskTotal.trim();\n        return diskTotal;\n    }\n\n    public synchronized String getDiskUsed() {\n\n        if (diskUsed != null) diskUsed = diskUsed.trim();\n        return diskUsed;\n    }\n\n    public synchronized String getDiskFree() {\n\n        if (diskFree != null) diskFree = diskFree.trim();\n        return diskFree;\n    }\n\n    public synchronized String getDiskUsage() {\n\n        if (diskUsage != null) diskUsage = diskUsage.trim();\n        return diskUsage;\n    }\n\n    public synchronized String getNoProcesses() {\n\n        if (processesNo != null) processesNo = processesNo.trim();\n        return processesNo;\n    }\n\n    public synchronized String getLoad1() {\n\n        if (load1 != null) load1 = load1.trim();\n        return load1;\n    }\n\n    public synchronized String getLoad5() {\n\n        if (load5 != null) load5 = load5.trim();\n        return load5;\n    }\n\n    public synchronized Hashtable getProcessesState() {\n        return states;\n    }\n\n    public synchronized Hashtable getNetSockets() {\n        return netSockets;\n    }\n\n    public synchronized Hashtable getTcpDetails() {\n        return netTcpDetails;\n    }\n\n    public synchronized String getLoad15() {\n\n        if (load15 != null) load15 = load15.trim();\n        return load15;\n    }\n\n    public synchronized String[] getNetInterfaces() {\n        return netInterfaces;\n    }\n\n    public synchronized String getNetIn(String netInterface) {\n\n        if (netIn.containsKey(netInterface)) {\n            String str = (String) netIn.get(netInterface);\n            if (str != null) str = str.trim();\n            return str;\n        }\n        return null;\n    }\n\n    public synchronized String getNetOut(String netInterface) {\n\n        if (netOut.containsKey(netInterface)) {\n            String str = (String) netOut.get(netInterface);\n            if (str != null) str = str.trim();\n            return str;\n        }\n        return null;\n    }\n\n    public void stopIt() {\n        exec.stopIt();\n    }\n\n    /**\n     * Computes the difference between the new value and the old value of a\n     * counter, considering the case when the counter reaches its maximum\n     * value and is reset. We assume the counter has 32 bits.\n     */\n    public long diffWithOverflowCheck(long newVal, long oldVal) {\n\n        if (newVal >= oldVal) {\n            return newVal - oldVal;\n        } else {\n            long vmax;\n            long p32 = 1L << 32;\n            long p64 = 1L << 64;\n            if (oldVal < p32)\n                vmax = p32;  // 32 bits\n            else\n                vmax = p64;  // 64 bits\n\n            return newVal - oldVal + vmax;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/apmon/host/cmdExec.java",
    "content": "package apmon.host;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Date;\nimport java.util.LinkedList;\n\npublic class cmdExec {\n\n    public String full_cmd;\n    public Process pro;\n    protected LinkedList streams = null;\n    protected LinkedList streamsReal = null;\n    protected boolean isError = false;\n    /* These varibles are set to true when we want to destroy the streams pool */\n    protected boolean stopStreams = false;\n    protected boolean stopStreamsReal = false;\n    String osname;\n    String exehome = \"\";\n    private long timeout = 60 * 1000; // 1 min\n\n    public cmdExec() {\n        osname = System.getProperty(\"os.name\");\n        exehome = System.getProperty(\"user.dir\");\n        String tot = System.getProperty(\"iperf.timeout\");\n        double dd = -1.0;\n        try {\n            dd = Double.parseDouble(tot);\n        } catch (Exception e) {\n            dd = -1.0;\n        }\n        if (dd >= 0.0) timeout = (long) (dd * 1000);\n        streams = new LinkedList();\n        streamsReal = new LinkedList();\n    }\n\n    public void setCmd(String cmd) {\n        osname = System.getProperty(\"os.name\");\n        full_cmd = cmd; // local\n    }\n\n    public void setTimeout(long timeout) {\n\n        this.timeout = timeout;\n    }\n\n    public BufferedReader procOutput(String cmd) {\n        try {\n\n            if (osname.startsWith(\"Linux\") || osname.startsWith(\"Mac\")) {\n                pro =\n                        Runtime.getRuntime().exec(\n                                new String[]{\"/bin/sh\", \"-c\", cmd});\n            } else if (osname.startsWith(\"Windows\")) {\n                pro = Runtime.getRuntime().exec(exehome + cmd);\n            }\n\n            InputStream out = pro.getInputStream();\n            BufferedReader br = new BufferedReader(new InputStreamReader(out));\n            BufferedReader err = new BufferedReader(new InputStreamReader(pro.getErrorStream()));\n\n            String buffer = \"\";\n            String ret = \"\";\n            while ((buffer = err.readLine()) != null) {\n                ret += buffer + \"\\n'\";\n            }\n\n            if (ret.length() != 0) {\n                return null;\n            }\n\n            return br;\n\n        } catch (Exception e) {\n            System.out.println(\"FAILED to execute cmd = \" + exehome + cmd);\n            Thread.currentThread().interrupt();\n        }\n\n        return null;\n    }\n\n    public BufferedReader exeHomeOutput(String cmd) {\n\n        try {\n\n            pro =\n                    Runtime.getRuntime().exec(\n                            new String[]{\"/bin/sh\", \"-c\", exehome + cmd});\n//\t\t\tSystem.out.println(\"/bin/sh -c \"+exehome + cmd);\n            InputStream out = pro.getInputStream();\n            BufferedReader br = new BufferedReader(new InputStreamReader(out));\n\n            BufferedReader err = new BufferedReader(new InputStreamReader(pro.getErrorStream()));\n\n            String buffer = \"\";\n            String ret = \"\";\n            while ((buffer = err.readLine()) != null) {\n                ret += buffer + \"\\n'\";\n            }\n\n            if (ret.length() != 0) {\n//\t\t\t\tSystem.out.println(ret);\n                return null;\n            }\n\n\n            return br;\n\n        } catch (Exception e) {\n            System.out.println(\"FAILED to execute cmd = \" + exehome + cmd);\n            Thread.currentThread().interrupt();\n        }\n\n        return null;\n    }\n\n    public void stopModule() {\n\n        if (this.pro != null)\n            this.pro.destroy();\n\n    }\n\n    public BufferedReader readProc(String filePath) {\n\n        try {\n            return new BufferedReader(new FileReader(filePath));\n        } catch (Exception e) {\n\n            return null;\n        }\n    }\n\n    public boolean isError() {\n\n        return isError;\n    }\n\n    public String executeCommand(String command, String expect) {\n\n        StreamGobbler output = null;\n        StreamGobbler error = null;\n\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1 || osName.indexOf(\"Mac\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamGobbler();\n            output = getStreamGobbler();\n\n            // any error message?\n            error.setInputStream(proc.getErrorStream());\n\n            // any output?\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            // any error???\n            long startTime = new Date().getTime();\n            while (true) {\n                out = error.getOutput();\n                try {\n                    if (!out.equals(\"\") && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.getOutput();\n                    if (out != \"\" && out.indexOf(expect) != -1) {\n                        isError = false;\n                        break;\n                    }\n                }\n                long endTime = new Date().getTime();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.equals(\"\"))\n                out = output.getOutput();\n\n//\t\t\tString ret = \"\";\n//\t\t\t\n//\t\t\tif (!error.getOutput().equals(\"\"))\n//\t\t\t\tret = error.getOutput();\n//\t\t\t\n//\t\t\tret = output.getOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamGobbler(error);\n            addStreamGobbler(output);\n\n            error = null;\n            output = null;\n\n            return out;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            isError = true;\n            return \"\";\n        }\n    }\n\n\n    public String executeCommand(String command, String expect, int howManyTimes) {\n\n        StreamGobbler output = null;\n        StreamGobbler error = null;\n        int nr = 0; // how many times the expect string occured\n\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1 || osName.indexOf(\"Mac\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamGobbler();\n            output = getStreamGobbler();\n\n            error.setInputStream(proc.getErrorStream());\n\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            long startTime = new Date().getTime();\n            while (true) {\n                out = error.getOutput();\n                try {\n                    if (!out.equals(\"\") && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.getOutput();\n                    if (out != \"\" && out.indexOf(expect) != -1) {\n                        nr = getStringOccurences(out, expect);\n                        if (nr >= howManyTimes) {\n                            isError = false;\n                            break;\n                        }\n                    }\n                }\n                long endTime = new Date().getTime();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.equals(\"\"))\n                out = output.getOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamGobbler(error);\n            addStreamGobbler(output);\n\n            error = null;\n            output = null;\n\n            return out;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            isError = true;\n            return \"\";\n        }\n    }\n\n    protected int getStringOccurences(String text, String token) {\n\n        if (text.indexOf(token) < 0) return 0;\n        int nr = 0;\n        String str = text;\n        while (str.indexOf(token) >= 0) {\n            str = str.substring(str.indexOf(token) + token.length());\n            nr++;\n        }\n        return nr;\n    }\n\n    // cipsm ->  new execute command - it shows the output exactly as it is, by lines\n    public String executeCommandReality(String command, String expect) {\n\n        StreamRealGobbler error = null;\n        StreamRealGobbler output = null;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamRealGobbler();\n            output = getStreamRealGobbler();\n\n            // any error message?\n            error.setInputStream(proc.getErrorStream());\n\n            // any output?\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            // any error???\n            long startTime = new Date().getTime();\n            while (true) {\n                out = error.forceAllOutput();\n                try {\n                    if (!out.equals(\"\") && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.forceAllOutput();\n                    if (out != \"\" && out.indexOf(expect) != -1) {\n                        isError = false;\n                        break;\n                    }\n                }\n                long endTime = new Date().getTime();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.equals(\"\"))\n                out = output.forceAllOutput();\n\n//\t\t\tString ret = \"\";\n//\t\t\t\n//\t\t\tif (!error.getOutput().equals(\"\"))\n//\t\t\t\tret = error.forceAllOutput();\n//\t\t\t\n//\t\t\tret = output.forceAllOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamRealGobbler(error);\n            addStreamRealGobbler(output);\n\n            error = null;\n            output = null;\n\n            return out;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamRealGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamRealGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            isError = true;\n\n            return \"\";\n        }\n    }\n\n    public String executeCommandReality(String command, String expect, int howManyTimes) {\n\n        StreamRealGobbler error = null;\n        StreamRealGobbler output = null;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamRealGobbler();\n            output = getStreamRealGobbler();\n\n            error.setInputStream(proc.getErrorStream());\n\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            long startTime = new Date().getTime();\n            while (true) {\n                out = error.forceAllOutput();\n                try {\n                    if (!out.equals(\"\") && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.forceAllOutput();\n                    if (out != \"\" && out.indexOf(expect) != -1) {\n                        int nr = getStringOccurences(out, expect);\n                        if (nr >= howManyTimes) {\n                            isError = false;\n                            break;\n                        }\n                    }\n                }\n                long endTime = new Date().getTime();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.equals(\"\"))\n                out = output.forceAllOutput();\n\n//\t\t\tString ret = \"\";\n//\t\t\t\n//\t\t\tif (!error.getOutput().equals(\"\"))\n//\t\t\t\tret = error.forceAllOutput();\n//\t\t\t\n//\t\t\tret = output.forceAllOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamRealGobbler(error);\n            addStreamRealGobbler(output);\n\n            error = null;\n            output = null;\n\n            return out;\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamRealGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamRealGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            isError = true;\n\n            return \"\";\n        }\n    }\n\n    public StreamGobbler getStreamGobbler() {\n\n        synchronized (streams) {\n            if (streams.size() == 0) {\n                StreamGobbler stream = new StreamGobbler(null);\n                stream.start();\n                return stream;\n            }\n            return (StreamGobbler) streams.removeFirst();\n        }\n    }\n\n    public void addStreamGobbler(StreamGobbler stream) {\n\n        synchronized (streams) {\n            if (!stopStreams)\n                streams.addLast(stream);\n            else\n                stream.stopItForever();\n        }\n    }\n\n    public StreamRealGobbler getStreamRealGobbler() {\n        synchronized (streamsReal) {\n            if (streamsReal.size() == 0) {\n                StreamRealGobbler stream = new StreamRealGobbler(null);\n                stream.start();\n                return stream;\n            }\n            return (StreamRealGobbler) streamsReal.removeFirst();\n        }\n    }\n\n    public void addStreamRealGobbler(StreamRealGobbler stream) {\n\n        synchronized (streamsReal) {\n            if (!stopStreamsReal)\n                streamsReal.addLast(stream);\n            else\n                stream.stopItForever();\n        }\n    }\n\n    public void stopIt() {\n        //System.out.println(\"### cmdExec stopIt streams.size = \" + streams.size());\n        synchronized (streams) {\n            stopStreams = true;\n\n            while (streams.size() > 0) {\n                StreamGobbler sg = (StreamGobbler) (streams.removeFirst());\n                sg.stopItForever();\n            }\n        }\n        synchronized (streamsReal) {\n            stopStreamsReal = true;\n\n            while (streamsReal.size() > 0) {\n                StreamRealGobbler sg = (StreamRealGobbler) (streamsReal.removeFirst());\n                sg.stopItForever();\n            }\n        }\n    }\n\n    class StreamGobbler extends Thread {\n\n        InputStream is;\n        String output = \"\";\n        boolean stop = false;\n        boolean stopForever = false;\n        boolean doneReading = false;\n\n        public StreamGobbler(InputStream is) {\n\n            super(\"Stream Gobler\");\n            this.is = is;\n            this.setDaemon(true);\n        }\n\n        public void setInputStream(InputStream is) {\n\n            this.is = is;\n            output = \"\";\n            stop = false;\n            synchronized (this) {\n                doneReading = false;\n                notify();\n            }\n        }\n\n        public String getOutput() {\n\n            return output;\n        }\n\n        public synchronized String forceAllOutput() {\n\n            if (!doneReading)\n                return \"\";\n            doneReading = false;\n            return output;\n        }\n\n        public void stopIt() {\n            stop = true;\n        }\n\n        public void stopItForever() {\n            synchronized (this) {\n                stopForever = true;\n                notify();\n            }\n        }\n\n        public void run() {\n\n            while (true) {\n\n                synchronized (this) {\n                    while (is == null && !stopForever) {\n                        try {\n                            wait();\n                        } catch (Exception e) {\n                        }\n                    }\n                }\n\n                if (stopForever) {\n                    break;\n                }\n                try {\n                    InputStreamReader isr = new InputStreamReader(is);\n                    BufferedReader br = new BufferedReader(isr);\n                    String line = null;\n                    while (!stop && (line = br.readLine()) != null) {\n                        output += line;\n                    }\n                    synchronized (this) {\n                        doneReading = true;\n                    }\n                    is.close();\n                } catch (Exception ioe) {\n                    output = \"\";\n                }\n                is = null;\n            }\n        }\n    }\n\n    class StreamRealGobbler extends Thread {\n\n        InputStream is;\n        String output = \"\";\n        boolean stop = false;\n        boolean doneReading = false;\n        boolean stopForever = false;\n\n        public StreamRealGobbler(InputStream is) {\n\n            super(\"Stream Real Gobbler\");\n            this.is = is;\n            this.setDaemon(true);\n        }\n\n        public void setInputStream(InputStream is) {\n\n            this.is = is;\n            output = \"\";\n            stop = false;\n            synchronized (this) {\n                doneReading = false;\n                notify();\n            }\n        }\n\n        public String getOutput() {\n\n            return output;\n        }\n\n        public synchronized String forceAllOutput() {\n\n            if (!doneReading)\n                return \"\";\n            return output;\n        }\n\n        public void stopIt() {\n            stop = true;\n        }\n\n        public void stopItForever() {\n            synchronized (this) {\n                stopForever = true;\n                notify();\n            }\n        }\n\n        public void run() {\n\n            while (true) {\n\n                synchronized (this) {\n                    while (is == null && !stopForever) {\n                        try {\n                            wait();\n                        } catch (Exception e) {\n                        }\n                    }\n                }\n\n                if (stopForever) {\n                    break;\n                }\n\n                try {\n                    InputStreamReader isr = new InputStreamReader(is);\n                    BufferedReader br = new BufferedReader(isr);\n                    String line = null;\n                    while (!stop && (line = br.readLine()) != null) {\n                        output += line + \"\\n\";\n                    }\n                    synchronized (this) {\n                        doneReading = true;\n                    }\n                } catch (Exception ioe) {\n                    output = \"\";\n                }\n                is = null;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/ch/ethz/ssh2/ChannelCondition.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * Contains constants that can be used to specify what conditions to wait for on\r\n * a SSH-2 channel (e.g., represented by a {@link Session}).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ChannelCondition.java,v 1.6 2006/08/11 12:24:00 cplattne Exp $\r\n * @see Session#waitForCondition(int, long)\r\n */\r\n\r\npublic abstract interface ChannelCondition {\r\n    /**\r\n     * A timeout has occurred, none of your requested conditions is fulfilled.\r\n     * However, other conditions may be true - therefore, NEVER use the \"==\"\r\n     * operator to test for this (or any other) condition. Always use\r\n     * something like <code>((cond & ChannelCondition.CLOSED) != 0)</code>.\r\n     */\r\n    public static final int TIMEOUT = 1;\r\n\r\n    /**\r\n     * The underlying SSH-2 channel, however not necessarily the whole connection,\r\n     * has been closed. This implies <code>EOF</code>. Note that there may still\r\n     * be unread stdout or stderr data in the local window, i.e, <code>STDOUT_DATA</code>\r\n     * or/and <code>STDERR_DATA</code> may be set at the same time.\r\n     */\r\n    public static final int CLOSED = 2;\r\n\r\n    /**\r\n     * There is stdout data available that is ready to be consumed.\r\n     */\r\n    public static final int STDOUT_DATA = 4;\r\n\r\n    /**\r\n     * There is stderr data available that is ready to be consumed.\r\n     */\r\n    public static final int STDERR_DATA = 8;\r\n\r\n    /**\r\n     * EOF on has been reached, no more _new_ stdout or stderr data will arrive\r\n     * from the remote server. However, there may be unread stdout or stderr\r\n     * data, i.e, <code>STDOUT_DATA</code> or/and <code>STDERR_DATA</code>\r\n     * may be set at the same time.\r\n     */\r\n    public static final int EOF = 16;\r\n\r\n    /**\r\n     * The exit status of the remote process is available.\r\n     * Some servers never send the exist status, or occasionally \"forget\" to do so.\r\n     */\r\n    public static final int EXIT_STATUS = 32;\r\n\r\n    /**\r\n     * The exit signal of the remote process is available.\r\n     */\r\n    public static final int EXIT_SIGNAL = 64;\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/Connection.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.auth.AuthenticationManager;\r\nimport ch.ethz.ssh2.channel.ChannelManager;\r\nimport ch.ethz.ssh2.crypto.CryptoWishList;\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;\r\nimport ch.ethz.ssh2.crypto.digest.MAC;\r\nimport ch.ethz.ssh2.transport.KexManager;\r\nimport ch.ethz.ssh2.transport.TransportManager;\r\nimport ch.ethz.ssh2.util.TimeoutService;\r\nimport ch.ethz.ssh2.util.TimeoutService.TimeoutToken;\r\n\r\nimport java.io.CharArrayWriter;\r\nimport java.io.File;\r\nimport java.io.FileReader;\r\nimport java.io.IOException;\r\nimport java.net.SocketTimeoutException;\r\nimport java.security.SecureRandom;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * A <code>Connection</code> is used to establish an encrypted TCP/IP\r\n * connection to a SSH-2 server.\r\n * <p>\r\n * Typically, one\r\n * <ol>\r\n * <li>creates a {@link #Connection(String) Connection} object.</li>\r\n * <li>calls the {@link #connect() connect()} method.</li>\r\n * <li>calls some of the authentication methods (e.g., {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}).</li>\r\n * <li>calls one or several times the {@link #openSession() openSession()} method.</li>\r\n * <li>finally, one must close the connection and release resources with the {@link #close() close()} method.</li>\r\n * </ol>\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Connection.java,v 1.28 2006/09/12 15:35:26 cplattne Exp $\r\n */\r\n\r\npublic class Connection {\r\n    /**\r\n     * The identifier presented to the SSH-2 server.\r\n     */\r\n    public final static String identification = \"Ganymed Build_210beta8\";\r\n\r\n\t/* Will be used to generate all random data needed for the current connection.\r\n     * Note: SecureRandom.nextBytes() is thread safe.\r\n\t */\r\n    private final String hostname;\r\n    private final int port;\r\n    private SecureRandom generator;\r\n    private AuthenticationManager am;\r\n    private boolean authenticated = false;\r\n    private ChannelManager cm;\r\n    private CryptoWishList cryptoWishList = new CryptoWishList();\r\n    private DHGexParameters dhgexpara = new DHGexParameters();\r\n    private TransportManager tm;\r\n    private boolean tcpNoDelay = false;\r\n    private ProxyData proxyData = null;\r\n    private Vector connectionMonitors = new Vector();\r\n\r\n    /**\r\n     * Prepares a fresh <code>Connection</code> object which can then be used\r\n     * to establish a connection to the specified SSH-2 server.\r\n     * <p>\r\n     * Same as {@link #Connection(String, int) Connection(hostname, 22)}.\r\n     *\r\n     * @param hostname the hostname of the SSH-2 server.\r\n     */\r\n    public Connection(String hostname) {\r\n        this(hostname, 22);\r\n    }\r\n\r\n    /**\r\n     * Prepares a fresh <code>Connection</code> object which can then be used\r\n     * to establish a connection to the specified SSH-2 server.\r\n     *\r\n     * @param hostname the host where we later want to connect to.\r\n     * @param port     port on the server, normally 22.\r\n     */\r\n    public Connection(String hostname, int port) {\r\n        this.hostname = hostname;\r\n        this.port = port;\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @return The list of supported cipher algorithms by this implementation.\r\n     */\r\n    public static synchronized String[] getAvailableCiphers() {\r\n        return BlockCipherFactory.getDefaultCipherList();\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @return The list of supported MAC algorthims by this implementation.\r\n     */\r\n    public static synchronized String[] getAvailableMACs() {\r\n        return MAC.getMacList();\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @return The list of supported server host key algorthims by this implementation.\r\n     */\r\n    public static synchronized String[] getAvailableServerHostKeyAlgorithms() {\r\n        return KexManager.getDefaultServerHostkeyAlgorithmList();\r\n    }\r\n\r\n    /**\r\n     * After a successful connect, one has to authenticate oneself. This method\r\n     * is based on DSA (it uses DSA to sign a challenge sent by the server).\r\n     * <p>\r\n     * If the authentication phase is complete, <code>true</code> will be\r\n     * returned. If the server does not accept the request (or if further\r\n     * authentication steps are needed), <code>false</code> is returned and\r\n     * one can retry either by using this or any other authentication method\r\n     * (use the <code>getRemainingAuthMethods</code> method to get a list of\r\n     * the remaining possible methods).\r\n     *\r\n     * @param user     A <code>String</code> holding the username.\r\n     * @param pem      A <code>String</code> containing the DSA private key of the\r\n     *                 user in OpenSSH key format (PEM, you can't miss the\r\n     *                 \"-----BEGIN DSA PRIVATE KEY-----\" tag). The string may contain\r\n     *                 linefeeds.\r\n     * @param password If the PEM string is 3DES encrypted (\"DES-EDE3-CBC\"), then you\r\n     *                 must specify the password. Otherwise, this argument will be\r\n     *                 ignored and can be set to <code>null</code>.\r\n     * @return whether the connection is now authenticated.\r\n     * @throws IOException\r\n     * @deprecated You should use one of the {@link #authenticateWithPublicKey(String, File, String) authenticateWithPublicKey()}\r\n     * methods, this method is just a wrapper for it and will\r\n     * disappear in future builds.\r\n     */\r\n    public synchronized boolean authenticateWithDSA(String user, String pem, String password) throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Connection is not established!\");\r\n\r\n        if (authenticated)\r\n            throw new IllegalStateException(\"Connection is already authenticated!\");\r\n\r\n        if (am == null)\r\n            am = new AuthenticationManager(tm);\r\n\r\n        if (cm == null)\r\n            cm = new ChannelManager(tm);\r\n\r\n        if (user == null)\r\n            throw new IllegalArgumentException(\"user argument is null\");\r\n\r\n        if (pem == null)\r\n            throw new IllegalArgumentException(\"pem argument is null\");\r\n\r\n        authenticated = am.authenticatePublicKey(user, pem.toCharArray(), password, getOrCreateSecureRND());\r\n\r\n        return authenticated;\r\n    }\r\n\r\n    /**\r\n     * A wrapper that calls {@link #authenticateWithKeyboardInteractive(String, String[], InteractiveCallback)\r\n     * authenticateWithKeyboardInteractivewith} a <code>null</code> submethod list.\r\n     *\r\n     * @param user A <code>String</code> holding the username.\r\n     * @param cb   An <code>InteractiveCallback</code> which will be used to\r\n     *             determine the responses to the questions asked by the server.\r\n     * @return whether the connection is now authenticated.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean authenticateWithKeyboardInteractive(String user, InteractiveCallback cb)\r\n            throws IOException {\r\n        return authenticateWithKeyboardInteractive(user, null, cb);\r\n    }\r\n\r\n    /**\r\n     * After a successful connect, one has to authenticate oneself. This method\r\n     * is based on \"keyboard-interactive\", specified in\r\n     * draft-ietf-secsh-auth-kbdinteract-XX. Basically, you have to define a\r\n     * callback object which will be feeded with challenges generated by the\r\n     * server. Answers are then sent back to the server. It is possible that the\r\n     * callback will be called several times during the invocation of this\r\n     * method (e.g., if the server replies to the callback's answer(s) with\r\n     * another challenge...)\r\n     * <p>\r\n     * If the authentication phase is complete, <code>true</code> will be\r\n     * returned. If the server does not accept the request (or if further\r\n     * authentication steps are needed), <code>false</code> is returned and\r\n     * one can retry either by using this or any other authentication method\r\n     * (use the <code>getRemainingAuthMethods</code> method to get a list of\r\n     * the remaining possible methods).\r\n     * <p>\r\n     * Note: some SSH servers advertise \"keyboard-interactive\", however, any\r\n     * interactive request will be denied (without having sent any challenge to\r\n     * the client).\r\n     *\r\n     * @param user       A <code>String</code> holding the username.\r\n     * @param submethods An array of submethod names, see\r\n     *                   draft-ietf-secsh-auth-kbdinteract-XX. May be <code>null</code>\r\n     *                   to indicate an empty list.\r\n     * @param cb         An <code>InteractiveCallback</code> which will be used to\r\n     *                   determine the responses to the questions asked by the server.\r\n     * @return whether the connection is now authenticated.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean authenticateWithKeyboardInteractive(String user, String[] submethods,\r\n                                                                    InteractiveCallback cb) throws IOException {\r\n        if (cb == null)\r\n            throw new IllegalArgumentException(\"Callback may not ne NULL!\");\r\n\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Connection is not established!\");\r\n\r\n        if (authenticated)\r\n            throw new IllegalStateException(\"Connection is already authenticated!\");\r\n\r\n        if (am == null)\r\n            am = new AuthenticationManager(tm);\r\n\r\n        if (cm == null)\r\n            cm = new ChannelManager(tm);\r\n\r\n        if (user == null)\r\n            throw new IllegalArgumentException(\"user argument is null\");\r\n\r\n        authenticated = am.authenticateInteractive(user, submethods, cb);\r\n\r\n        return authenticated;\r\n    }\r\n\r\n    /**\r\n     * After a successfull connect, one has to authenticate oneself. This method\r\n     * sends username and password to the server.\r\n     * <p>\r\n     * If the authentication phase is complete, <code>true</code> will be\r\n     * returned. If the server does not accept the request (or if further\r\n     * authentication steps are needed), <code>false</code> is returned and\r\n     * one can retry either by using this or any other authentication method\r\n     * (use the <code>getRemainingAuthMethods</code> method to get a list of\r\n     * the remaining possible methods).\r\n     * <p>\r\n     * Note: if this method fails, then please double-check that it is actually\r\n     * offered by the server (use {@link #getRemainingAuthMethods(String) getRemainingAuthMethods()}.\r\n     * <p>\r\n     * Often, password authentication is disabled, but users are not aware of it.\r\n     * Many servers only offer \"publickey\" and \"keyboard-interactive\". However,\r\n     * even though \"keyboard-interactive\" *feels* like password authentication\r\n     * (e.g., when using the putty or openssh clients) it is *not* the same mechanism.\r\n     *\r\n     * @param user\r\n     * @param password\r\n     * @return if the connection is now authenticated.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean authenticateWithPassword(String user, String password) throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Connection is not established!\");\r\n\r\n        if (authenticated)\r\n            throw new IllegalStateException(\"Connection is already authenticated!\");\r\n\r\n        if (am == null)\r\n            am = new AuthenticationManager(tm);\r\n\r\n        if (cm == null)\r\n            cm = new ChannelManager(tm);\r\n\r\n        if (user == null)\r\n            throw new IllegalArgumentException(\"user argument is null\");\r\n\r\n        if (password == null)\r\n            throw new IllegalArgumentException(\"password argument is null\");\r\n\r\n        authenticated = am.authenticatePassword(user, password);\r\n\r\n        return authenticated;\r\n    }\r\n\r\n    /**\r\n     * After a successful connect, one has to authenticate oneself.\r\n     * The authentication method \"publickey\" works by signing a challenge\r\n     * sent by the server. The signature is either DSA or RSA based - it\r\n     * just depends on the type of private key you specify, either a DSA\r\n     * or RSA private key in PEM format. And yes, this is may seem to be a\r\n     * little confusing, the method is called \"publickey\" in the SSH-2 protocol\r\n     * specification, however since we need to generate a signature, you\r\n     * actually have to supply a private key =).\r\n     * <p>\r\n     * The private key contained in the PEM file may also be encrypted (\"Proc-Type: 4,ENCRYPTED\").\r\n     * The library supports DES-CBC and DES-EDE3-CBC encryption, as well\r\n     * as the more exotic PEM encrpytions AES-128-CBC, AES-192-CBC and AES-256-CBC.\r\n     * <p>\r\n     * If the authentication phase is complete, <code>true</code> will be\r\n     * returned. If the server does not accept the request (or if further\r\n     * authentication steps are needed), <code>false</code> is returned and\r\n     * one can retry either by using this or any other authentication method\r\n     * (use the <code>getRemainingAuthMethods</code> method to get a list of\r\n     * the remaining possible methods).\r\n     * <p>\r\n     * NOTE PUTTY USERS: Event though your key file may start with \"-----BEGIN...\"\r\n     * it is not in the expected format. You have to convert it to the OpenSSH\r\n     * key format by using the \"puttygen\" tool (can be downloaded from the Putty\r\n     * website). Simply load your key and then use the \"Conversions/Export OpenSSH key\"\r\n     * functionality to get a proper PEM file.\r\n     *\r\n     * @param user          A <code>String</code> holding the username.\r\n     * @param pemPrivateKey A <code>char[]</code> containing a DSA or RSA private key of the\r\n     *                      user in OpenSSH key format (PEM, you can't miss the\r\n     *                      \"-----BEGIN DSA PRIVATE KEY-----\" or \"-----BEGIN RSA PRIVATE KEY-----\"\r\n     *                      tag). The char array may contain linebreaks/linefeeds.\r\n     * @param password      If the PEM structure is encrypted (\"Proc-Type: 4,ENCRYPTED\") then\r\n     *                      you must specify a password. Otherwise, this argument will be ignored\r\n     *                      and can be set to <code>null</code>.\r\n     * @return whether the connection is now authenticated.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean authenticateWithPublicKey(String user, char[] pemPrivateKey, String password)\r\n            throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Connection is not established!\");\r\n\r\n        if (authenticated)\r\n            throw new IllegalStateException(\"Connection is already authenticated!\");\r\n\r\n        if (am == null)\r\n            am = new AuthenticationManager(tm);\r\n\r\n        if (cm == null)\r\n            cm = new ChannelManager(tm);\r\n\r\n        if (user == null)\r\n            throw new IllegalArgumentException(\"user argument is null\");\r\n\r\n        if (pemPrivateKey == null)\r\n            throw new IllegalArgumentException(\"pemPrivateKey argument is null\");\r\n\r\n        authenticated = am.authenticatePublicKey(user, pemPrivateKey, password, getOrCreateSecureRND());\r\n\r\n        return authenticated;\r\n    }\r\n\r\n    /**\r\n     * A convenience wrapper function which reads in a private key (PEM format, either DSA or RSA)\r\n     * and then calls <code>authenticateWithPublicKey(String, char[], String)</code>.\r\n     * <p>\r\n     * NOTE PUTTY USERS: Event though your key file may start with \"-----BEGIN...\"\r\n     * it is not in the expected format. You have to convert it to the OpenSSH\r\n     * key format by using the \"puttygen\" tool (can be downloaded from the Putty\r\n     * website). Simply load your key and then use the \"Conversions/Export OpenSSH key\"\r\n     * functionality to get a proper PEM file.\r\n     *\r\n     * @param user     A <code>String</code> holding the username.\r\n     * @param pemFile  A <code>File</code> object pointing to a file containing a DSA or RSA\r\n     *                 private key of the user in OpenSSH key format (PEM, you can't miss the\r\n     *                 \"-----BEGIN DSA PRIVATE KEY-----\" or \"-----BEGIN RSA PRIVATE KEY-----\"\r\n     *                 tag).\r\n     * @param password If the PEM file is encrypted then you must specify the password.\r\n     *                 Otherwise, this argument will be ignored and can be set to <code>null</code>.\r\n     * @return whether the connection is now authenticated.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean authenticateWithPublicKey(String user, File pemFile, String password)\r\n            throws IOException {\r\n        if (pemFile == null)\r\n            throw new IllegalArgumentException(\"pemFile argument is null\");\r\n\r\n        char[] buff = new char[256];\r\n\r\n        CharArrayWriter cw = new CharArrayWriter();\r\n\r\n        FileReader fr = new FileReader(pemFile);\r\n\r\n        while (true) {\r\n            int len = fr.read(buff);\r\n            if (len < 0)\r\n                break;\r\n            cw.write(buff, 0, len);\r\n        }\r\n\r\n        fr.close();\r\n\r\n        return authenticateWithPublicKey(user, cw.toCharArray(), password);\r\n    }\r\n\r\n    /**\r\n     * Add a {@link ConnectionMonitor} to this connection. Can be invoked at any time,\r\n     * but it is best to add connection monitors before invoking\r\n     * <code>connect()</code> to avoid glitches (e.g., you add a connection monitor after\r\n     * a successful connect(), but the connection has died in the mean time. Then,\r\n     * your connection monitor won't be notified.)\r\n     * <p>\r\n     * You can add as many monitors as you like.\r\n     *\r\n     * @param cmon An object implementing the <code>ConnectionMonitor</code> interface.\r\n     * @see ConnectionMonitor\r\n     */\r\n    public synchronized void addConnectionMonitor(ConnectionMonitor cmon) {\r\n        if (cmon == null)\r\n            throw new IllegalArgumentException(\"cmon argument is null\");\r\n\r\n        connectionMonitors.addElement(cmon);\r\n\r\n        if (tm != null)\r\n            tm.setConnectionMonitors(connectionMonitors);\r\n    }\r\n\r\n    /**\r\n     * Close the connection to the SSH-2 server. All assigned sessions will be\r\n     * closed, too. Can be called at any time. Don't forget to call this once\r\n     * you don't need a connection anymore - otherwise the receiver thread may\r\n     * run forever.\r\n     */\r\n    public synchronized void close() {\r\n        Throwable t = new Throwable(\"Closed due to user request.\");\r\n        close(t, false);\r\n    }\r\n\r\n    private void close(Throwable t, boolean hard) {\r\n        if (cm != null)\r\n            cm.closeAllChannels();\r\n\r\n        if (tm != null) {\r\n            tm.close(t, hard == false);\r\n            tm = null;\r\n        }\r\n        am = null;\r\n        cm = null;\r\n        authenticated = false;\r\n    }\r\n\r\n    /**\r\n     * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(null, 0, 0)}.\r\n     *\r\n     * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.\r\n     * @throws IOException\r\n     */\r\n    public synchronized ConnectionInfo connect() throws IOException {\r\n        return connect(null, 0, 0);\r\n    }\r\n\r\n    /**\r\n     * Same as {@link #connect(ServerHostKeyVerifier, int, int) connect(verifier, 0, 0)}.\r\n     *\r\n     * @return see comments for the {@link #connect(ServerHostKeyVerifier, int, int) connect(ServerHostKeyVerifier, int, int)} method.\r\n     * @throws IOException\r\n     */\r\n    public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier) throws IOException {\r\n        return connect(verifier, 0, 0);\r\n    }\r\n\r\n    /**\r\n     * Connect to the SSH-2 server and, as soon as the server has presented its\r\n     * host key, use the {@link ServerHostKeyVerifier#verifyServerHostKey(String,\r\n     * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()}\r\n     * method of the <code>verifier</code> to ask for permission to proceed.\r\n     * If <code>verifier</code> is <code>null</code>, then any host key will be\r\n     * accepted - this is NOT recommended, since it makes man-in-the-middle attackes\r\n     * VERY easy (somebody could put a proxy SSH server between you and the real server).\r\n     * <p>\r\n     * Note: The verifier will be called before doing any crypto calculations\r\n     * (i.e., diffie-hellman). Therefore, if you don't like the presented host key then\r\n     * no CPU cycles are wasted (and the evil server has less information about us).\r\n     * <p>\r\n     * However, it is still possible that the server presented a fake host key: the server\r\n     * cheated (typically a sign for a man-in-the-middle attack) and is not able to generate\r\n     * a signature that matches its host key. Don't worry, the library will detect such\r\n     * a scenario later when checking the signature (the signature cannot be checked before\r\n     * having completed the diffie-hellman exchange).\r\n     * <p>\r\n     * Note 2: The  {@link ServerHostKeyVerifier#verifyServerHostKey(String,\r\n     * int, String, byte[]) ServerHostKeyVerifier.verifyServerHostKey()} method\r\n     * will *NOT* be called from the current thread, the call is being made from a\r\n     * background thread (there is a background dispatcher thread for every\r\n     * established connection).\r\n     * <p>\r\n     * Note 3: This method will block as long as the key exchange of the underlying connection\r\n     * has not been completed (and you have not specified any timeouts).\r\n     * <p>\r\n     * Note 4: If you want to re-use a connection object that was successfully connected,\r\n     * then you must call the {@link #close()} method before invoking <code>connect()</code> again.\r\n     *\r\n     * @param verifier       An object that implements the\r\n     *                       {@link ServerHostKeyVerifier} interface. Pass <code>null</code>\r\n     *                       to accept any server host key - NOT recommended.\r\n     * @param connectTimeout Connect the underlying TCP socket to the server with the given timeout\r\n     *                       value (non-negative, in milliseconds). Zero means no timeout. If a proxy is being\r\n     *                       used (see {@link #setProxyData(ProxyData)}), then this timeout is used for the\r\n     *                       connection establishment to the proxy.\r\n     * @param kexTimeout     Timeout for complete connection establishment (non-negative,\r\n     *                       in milliseconds). Zero means no timeout. The timeout counts from the\r\n     *                       moment you invoke the connect() method and is cancelled as soon as the\r\n     *                       first key-exchange round has finished. It is possible that\r\n     *                       the timeout event will be fired during the invocation of the\r\n     *                       <code>verifier</code> callback, but it will only have an effect after\r\n     *                       the <code>verifier</code> returns.\r\n     * @return A {@link ConnectionInfo} object containing the details of\r\n     * the established connection.\r\n     * @throws IOException If any problem occurs, e.g., the server's host key is not\r\n     *                     accepted by the <code>verifier</code> or there is problem during\r\n     *                     the initial crypto setup (e.g., the signature sent by the server is wrong).\r\n     *                     <p>\r\n     *                     In case of a timeout (either connectTimeout or kexTimeout)\r\n     *                     a SocketTimeoutException is thrown.\r\n     *                     <p>\r\n     *                     An exception may also be thrown if the connection was already successfully\r\n     *                     connected (no matter if the connection broke in the mean time) and you invoke\r\n     *                     <code>connect()</code> again without having called {@link #close()} first.\r\n     *                     <p>\r\n     *                     If a HTTP proxy is being used and the proxy refuses the connection,\r\n     *                     then a {@link HTTPProxyException} may be thrown, which\r\n     *                     contains the details returned by the proxy. If the proxy is buggy and does\r\n     *                     not return a proper HTTP response, then a normal IOException is thrown instead.\r\n     */\r\n    public synchronized ConnectionInfo connect(ServerHostKeyVerifier verifier, int connectTimeout, int kexTimeout)\r\n            throws IOException {\r\n        final class TimeoutState {\r\n            boolean isCancelled = false;\r\n            boolean timeoutSocketClosed = false;\r\n        }\r\n\r\n        if (tm != null)\r\n            throw new IOException(\"Connection to \" + hostname + \" is already in connected state!\");\r\n\r\n        if (connectTimeout < 0)\r\n            throw new IllegalArgumentException(\"connectTimeout must be non-negative!\");\r\n\r\n        if (kexTimeout < 0)\r\n            throw new IllegalArgumentException(\"kexTimeout must be non-negative!\");\r\n\r\n        final TimeoutState state = new TimeoutState();\r\n\r\n        tm = new TransportManager(hostname, port);\r\n\r\n        tm.setConnectionMonitors(connectionMonitors);\r\n\r\n\t\t/* Make sure that the runnable below will observe the new value of \"tm\"\r\n\t\t * and \"state\" (the runnable will be executed in a different thread, which\r\n\t\t * may be already running, that is why we need a memory barrier here).\r\n\t\t * See also the comment in Channel.java if you\r\n\t\t * are interested in the details.\r\n\t\t * \r\n\t\t * OKOK, this is paranoid since adding the runnable to the todo list\r\n\t\t * of the TimeoutService will ensure that all writes have been flushed\r\n\t\t * before the Runnable reads anything\r\n\t\t * (there is a synchronized block in TimeoutService.addTimeoutHandler).\r\n\t\t */\r\n\r\n        synchronized (tm) {\r\n\t\t\t/* We could actually synchronize on anything. */\r\n        }\r\n\r\n        try {\r\n            TimeoutToken token = null;\r\n\r\n            if (kexTimeout > 0) {\r\n                final Runnable timeoutHandler = new Runnable() {\r\n                    public void run() {\r\n                        synchronized (state) {\r\n                            if (state.isCancelled)\r\n                                return;\r\n                            state.timeoutSocketClosed = true;\r\n                            tm.close(new SocketTimeoutException(\"The connect timeout expired\"), false);\r\n                        }\r\n                    }\r\n                };\r\n\r\n                long timeoutHorizont = System.currentTimeMillis() + kexTimeout;\r\n\r\n                token = TimeoutService.addTimeoutHandler(timeoutHorizont, timeoutHandler);\r\n            }\r\n\r\n            try {\r\n                tm.initialize(cryptoWishList, verifier, dhgexpara, connectTimeout, getOrCreateSecureRND(), proxyData);\r\n            } catch (SocketTimeoutException se) {\r\n                throw (SocketTimeoutException) new SocketTimeoutException(\r\n                        \"The connect() operation on the socket timed out.\").initCause(se);\r\n            }\r\n\r\n            tm.setTcpNoDelay(tcpNoDelay);\r\n\r\n\t\t\t/* Wait until first KEX has finished */\r\n\r\n            ConnectionInfo ci = tm.getConnectionInfo(1);\r\n\r\n\t\t\t/* Now try to cancel the timeout, if needed */\r\n\r\n            if (token != null) {\r\n                TimeoutService.cancelTimeoutHandler(token);\r\n\r\n\t\t\t\t/* Were we too late? */\r\n\r\n                synchronized (state) {\r\n                    if (state.timeoutSocketClosed)\r\n                        throw new IOException(\"This exception will be replaced by the one below =)\");\r\n\t\t\t\t\t/* Just in case the \"cancelTimeoutHandler\" invocation came just a little bit\r\n\t\t\t\t\t * too late but the handler did not enter the semaphore yet - we can\r\n\t\t\t\t\t * still stop it.\r\n\t\t\t\t\t */\r\n                    state.isCancelled = true;\r\n                }\r\n            }\r\n\r\n            return ci;\r\n        } catch (SocketTimeoutException ste) {\r\n            throw ste;\r\n        } catch (IOException e1) {\r\n\t\t\t/* This will also invoke any registered connection monitors */\r\n            close(new Throwable(\"There was a problem during connect.\"), false);\r\n\r\n            synchronized (state) {\r\n\t\t\t\t/* Show a clean exception, not something like \"the socket is closed!?!\" */\r\n                if (state.timeoutSocketClosed)\r\n                    throw new SocketTimeoutException(\"The kexTimeout (\" + kexTimeout + \" ms) expired.\");\r\n            }\r\n\r\n\t\t\t/* Do not wrap a HTTPProxyException */\r\n            if (e1 instanceof HTTPProxyException)\r\n                throw e1;\r\n\r\n            throw (IOException) new IOException(\"There was a problem while connecting to \" + hostname + \":\" + port)\r\n                    .initCause(e1);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Creates a new {@link LocalPortForwarder}.\r\n     * A <code>LocalPortForwarder</code> forwards TCP/IP connections that arrive at a local\r\n     * port via the secure tunnel to another host (which may or may not be\r\n     * identical to the remote SSH-2 server).\r\n     * <p>\r\n     * This method must only be called after one has passed successfully the authentication step.\r\n     * There is no limit on the number of concurrent forwardings.\r\n     *\r\n     * @param local_port      the local port the LocalPortForwarder shall bind to.\r\n     * @param host_to_connect target address (IP or hostname)\r\n     * @param port_to_connect target port\r\n     * @return A {@link LocalPortForwarder} object.\r\n     * @throws IOException\r\n     */\r\n    public synchronized LocalPortForwarder createLocalPortForwarder(int local_port, String host_to_connect,\r\n                                                                    int port_to_connect) throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Cannot forward ports, you need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"Cannot forward ports, connection is not authenticated.\");\r\n\r\n        return new LocalPortForwarder(cm, local_port, host_to_connect, port_to_connect);\r\n    }\r\n\r\n    /**\r\n     * Creates a new {@link LocalStreamForwarder}.\r\n     * A <code>LocalStreamForwarder</code> manages an Input/Outputstream pair\r\n     * that is being forwarded via the secure tunnel into a TCP/IP connection to another host\r\n     * (which may or may not be identical to the remote SSH-2 server).\r\n     *\r\n     * @param host_to_connect\r\n     * @param port_to_connect\r\n     * @return A {@link LocalStreamForwarder} object.\r\n     * @throws IOException\r\n     */\r\n    public synchronized LocalStreamForwarder createLocalStreamForwarder(String host_to_connect, int port_to_connect)\r\n            throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Cannot forward, you need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"Cannot forward, connection is not authenticated.\");\r\n\r\n        return new LocalStreamForwarder(cm, host_to_connect, port_to_connect);\r\n    }\r\n\r\n    /**\r\n     * Create a very basic {@link SCPClient} that can be used to copy\r\n     * files from/to the SSH-2 server.\r\n     * <p>\r\n     * Works only after one has passed successfully the authentication step.\r\n     * There is no limit on the number of concurrent SCP clients.\r\n     * <p>\r\n     * Note: This factory method will probably disappear in the future.\r\n     *\r\n     * @return A {@link SCPClient} object.\r\n     * @throws IOException\r\n     */\r\n    public synchronized SCPClient createSCPClient() throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Cannot create SCP client, you need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"Cannot create SCP client, connection is not authenticated.\");\r\n\r\n        return new SCPClient(this);\r\n    }\r\n\r\n    /**\r\n     * Force an asynchronous key re-exchange (the call does not block). The\r\n     * latest values set for MAC, Cipher and DH group exchange parameters will\r\n     * be used. If a key exchange is currently in progress, then this method has\r\n     * the only effect that the so far specified parameters will be used for the\r\n     * next (server driven) key exchange.\r\n     * <p>\r\n     * Note: This implementation will never start a key exchange (other than the initial one)\r\n     * unless you or the SSH-2 server ask for it.\r\n     *\r\n     * @throws IOException In case of any failure behind the scenes.\r\n     */\r\n    public synchronized void forceKeyExchange() throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"You need to establish a connection first.\");\r\n\r\n        tm.forceKeyExchange(cryptoWishList, dhgexpara);\r\n    }\r\n\r\n    /**\r\n     * Returns the hostname that was passed to the constructor.\r\n     *\r\n     * @return the hostname\r\n     */\r\n    public synchronized String getHostname() {\r\n        return hostname;\r\n    }\r\n\r\n    /**\r\n     * Returns the port that was passed to the constructor.\r\n     *\r\n     * @return the TCP port\r\n     */\r\n    public synchronized int getPort() {\r\n        return port;\r\n    }\r\n\r\n    /**\r\n     * Returns a {@link ConnectionInfo} object containing the details of\r\n     * the connection. Can be called as soon as the connection has been\r\n     * established (successfully connected).\r\n     *\r\n     * @return A {@link ConnectionInfo} object.\r\n     * @throws IOException In case of any failure behind the scenes.\r\n     */\r\n    public synchronized ConnectionInfo getConnectionInfo() throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\r\n                    \"Cannot get details of connection, you need to establish a connection first.\");\r\n        return tm.getConnectionInfo(1);\r\n    }\r\n\r\n    /**\r\n     * After a successful connect, one has to authenticate oneself. This method\r\n     * can be used to tell which authentication methods are supported by the\r\n     * server at a certain stage of the authentication process (for the given\r\n     * username).\r\n     * <p>\r\n     * Note 1: the username will only be used if no authentication step was done\r\n     * so far (it will be used to ask the server for a list of possible\r\n     * authentication methods). Otherwise, this method ignores the user name and\r\n     * returns a cached method list (which is based on the information contained\r\n     * in the last negative server response).\r\n     * <p>\r\n     * Note 2: the server may return method names that are not supported by this\r\n     * implementation.\r\n     * <p>\r\n     * After a successful authentication, this method must not be called\r\n     * anymore.\r\n     *\r\n     * @param user A <code>String</code> holding the username.\r\n     * @return a (possibly emtpy) array holding authentication method names.\r\n     * @throws IOException\r\n     */\r\n    public synchronized String[] getRemainingAuthMethods(String user) throws IOException {\r\n        if (user == null)\r\n            throw new IllegalArgumentException(\"user argument may not be NULL!\");\r\n\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Connection is not established!\");\r\n\r\n        if (authenticated)\r\n            throw new IllegalStateException(\"Connection is already authenticated!\");\r\n\r\n        if (am == null)\r\n            am = new AuthenticationManager(tm);\r\n\r\n        if (cm == null)\r\n            cm = new ChannelManager(tm);\r\n\r\n        return am.getRemainingMethods(user);\r\n    }\r\n\r\n    /**\r\n     * Determines if the authentication phase is complete. Can be called at any\r\n     * time.\r\n     *\r\n     * @return <code>true</code> if no further authentication steps are\r\n     * needed.\r\n     */\r\n    public synchronized boolean isAuthenticationComplete() {\r\n        return authenticated;\r\n    }\r\n\r\n    /**\r\n     * Returns true if there was at least one failed authentication request and\r\n     * the last failed authentication request was marked with \"partial success\"\r\n     * by the server. This is only needed in the rare case of SSH-2 server setups\r\n     * that cannot be satisfied with a single successful authentication request\r\n     * (i.e., multiple authentication steps are needed.)\r\n     * <p>\r\n     * If you are interested in the details, then have a look at\r\n     * draft-ietf-secsh-userauth-XX.txt.\r\n     *\r\n     * @return if the there was a failed authentication step and the last one\r\n     * was marked as a \"partial success\".\r\n     */\r\n    public synchronized boolean isAuthenticationPartialSuccess() {\r\n        if (am == null)\r\n            return false;\r\n\r\n        return am.getPartialSuccess();\r\n    }\r\n\r\n    /**\r\n     * Checks if a specified authentication method is available. This method is\r\n     * actually just a wrapper for {@link #getRemainingAuthMethods(String)\r\n     * getRemainingAuthMethods()}.\r\n     *\r\n     * @param user   A <code>String</code> holding the username.\r\n     * @param method An authentication method name (e.g., \"publickey\", \"password\",\r\n     *               \"keyboard-interactive\") as specified by the SSH-2 standard.\r\n     * @return if the specified authentication method is currently available.\r\n     * @throws IOException\r\n     */\r\n    public synchronized boolean isAuthMethodAvailable(String user, String method) throws IOException {\r\n        if (method == null)\r\n            throw new IllegalArgumentException(\"method argument may not be NULL!\");\r\n\r\n        String methods[] = getRemainingAuthMethods(user);\r\n\r\n        for (int i = 0; i < methods.length; i++) {\r\n            if (methods[i].compareTo(method) == 0)\r\n                return true;\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    private final SecureRandom getOrCreateSecureRND() {\r\n        if (generator == null)\r\n            generator = new SecureRandom();\r\n\r\n        return generator;\r\n    }\r\n\r\n    /**\r\n     * Open a new {@link Session} on this connection. Works only after one has passed\r\n     * successfully the authentication step. There is no limit on the number of\r\n     * concurrent sessions.\r\n     *\r\n     * @return A {@link Session} object.\r\n     * @throws IOException\r\n     */\r\n    public synchronized Session openSession() throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"Cannot open session, you need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"Cannot open session, connection is not authenticated.\");\r\n\r\n        return new Session(cm, getOrCreateSecureRND());\r\n    }\r\n\r\n    /**\r\n     * Removes duplicates from a String array, keeps only first occurence\r\n     * of each element. Does not destroy order of elements; can handle nulls.\r\n     * Uses a very efficient O(N^2) algorithm =)\r\n     *\r\n     * @param list a String array.\r\n     * @return a cleaned String array.\r\n     */\r\n    private String[] removeDuplicates(String[] list) {\r\n        if ((list == null) || (list.length < 2))\r\n            return list;\r\n\r\n        String[] list2 = new String[list.length];\r\n\r\n        int count = 0;\r\n\r\n        for (int i = 0; i < list.length; i++) {\r\n            boolean duplicate = false;\r\n\r\n            String element = list[i];\r\n\r\n            for (int j = 0; j < count; j++) {\r\n                if (((element == null) && (list2[j] == null)) || ((element != null) && (element.equals(list2[j])))) {\r\n                    duplicate = true;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (duplicate)\r\n                continue;\r\n\r\n            list2[count++] = list[i];\r\n        }\r\n\r\n        if (count == list2.length)\r\n            return list2;\r\n\r\n        String[] tmp = new String[count];\r\n        System.arraycopy(list2, 0, tmp, 0, count);\r\n\r\n        return tmp;\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param ciphers\r\n     */\r\n    public synchronized void setClient2ServerCiphers(String[] ciphers) {\r\n        if ((ciphers == null) || (ciphers.length == 0))\r\n            throw new IllegalArgumentException();\r\n        ciphers = removeDuplicates(ciphers);\r\n        BlockCipherFactory.checkCipherList(ciphers);\r\n        cryptoWishList.c2s_enc_algos = ciphers;\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param macs\r\n     */\r\n    public synchronized void setClient2ServerMACs(String[] macs) {\r\n        if ((macs == null) || (macs.length == 0))\r\n            throw new IllegalArgumentException();\r\n        macs = removeDuplicates(macs);\r\n        MAC.checkMacList(macs);\r\n        cryptoWishList.c2s_mac_algos = macs;\r\n    }\r\n\r\n    /**\r\n     * Sets the parameters for the diffie-hellman group exchange. Unless you\r\n     * know what you are doing, you will never need this. Default values are\r\n     * defined in the {@link DHGexParameters} class.\r\n     *\r\n     * @param dgp {@link DHGexParameters}, non null.\r\n     */\r\n    public synchronized void setDHGexParameters(DHGexParameters dgp) {\r\n        if (dgp == null)\r\n            throw new IllegalArgumentException();\r\n\r\n        dhgexpara = dgp;\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param ciphers\r\n     */\r\n    public synchronized void setServer2ClientCiphers(String[] ciphers) {\r\n        if ((ciphers == null) || (ciphers.length == 0))\r\n            throw new IllegalArgumentException();\r\n        ciphers = removeDuplicates(ciphers);\r\n        BlockCipherFactory.checkCipherList(ciphers);\r\n        cryptoWishList.s2c_enc_algos = ciphers;\r\n    }\r\n\r\n    /**\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param macs\r\n     */\r\n    public synchronized void setServer2ClientMACs(String[] macs) {\r\n        if ((macs == null) || (macs.length == 0))\r\n            throw new IllegalArgumentException();\r\n\r\n        macs = removeDuplicates(macs);\r\n        MAC.checkMacList(macs);\r\n        cryptoWishList.s2c_mac_algos = macs;\r\n    }\r\n\r\n    /**\r\n     * Define the set of allowed server host key algorithms to be used for\r\n     * the following key exchange operations.\r\n     * <p>\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param algos An array of allowed server host key algorithms.\r\n     *              SSH-2 defines <code>ssh-dss</code> and <code>ssh-rsa</code>.\r\n     *              The entries of the array must be ordered after preference, i.e.,\r\n     *              the entry at index 0 is the most preferred one. You must specify\r\n     *              at least one entry.\r\n     */\r\n    public synchronized void setServerHostKeyAlgorithms(String[] algos) {\r\n        if ((algos == null) || (algos.length == 0))\r\n            throw new IllegalArgumentException();\r\n\r\n        algos = removeDuplicates(algos);\r\n        KexManager.checkServerHostkeyAlgorithmsList(algos);\r\n        cryptoWishList.serverHostKeyAlgorithms = algos;\r\n    }\r\n\r\n    /**\r\n     * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm) on the underlying socket.\r\n     * <p>\r\n     * Can be called at any time. If the connection has not yet been established\r\n     * then the passed value will be stored and set after the socket has been set up.\r\n     * The default value that will be used is <code>false</code>.\r\n     *\r\n     * @param enable the argument passed to the <code>Socket.setTCPNoDelay()</code> method.\r\n     * @throws IOException\r\n     */\r\n    public synchronized void setTCPNoDelay(boolean enable) throws IOException {\r\n        tcpNoDelay = enable;\r\n\r\n        if (tm != null)\r\n            tm.setTcpNoDelay(enable);\r\n    }\r\n\r\n    /**\r\n     * Used to tell the library that the connection shall be established through a proxy server.\r\n     * It only makes sense to call this method before calling the {@link #connect() connect()}\r\n     * method.\r\n     * <p>\r\n     * At the moment, only HTTP proxies are supported.\r\n     * <p>\r\n     * Note: This method can be called any number of times. The {@link #connect() connect()}\r\n     * method will use the value set in the last preceding invocation of this method.\r\n     *\r\n     * @param proxyData Connection information about the proxy. If <code>null</code>, then\r\n     *                  no proxy will be used (non surprisingly, this is also the default).\r\n     * @see HTTPProxyData\r\n     */\r\n    public synchronized void setProxyData(ProxyData proxyData) {\r\n        this.proxyData = proxyData;\r\n    }\r\n\r\n    /**\r\n     * Request a remote port forwarding.\r\n     * If successful, then forwarded connections will be redirected to the given target address.\r\n     * You can cancle a requested remote port forwarding by calling\r\n     * {@link #cancelRemotePortForwarding(int) cancelRemotePortForwarding()}.\r\n     * <p>\r\n     * A call of this method will block until the peer either agreed or disagreed to your request-\r\n     * <p>\r\n     * Note 1: this method typically fails if you\r\n     * <ul>\r\n     * <li>pass a port number for which the used remote user has not enough permissions (i.e., port\r\n     * &lt; 1024)</li>\r\n     * <li>or pass a port number that is already in use on the remote server</li>\r\n     * <li>or if remote port forwarding is disabled on the server.</li>\r\n     * </ul>\r\n     * <p>\r\n     * Note 2: (from the openssh man page): By default, the listening socket on the server will be\r\n     * bound to the loopback interface only. This may be overriden by specifying a bind address.\r\n     * Specifying a remote bind address will only succeed if the server's <b>GatewayPorts</b> option\r\n     * is enabled (see sshd_config(5)).\r\n     *\r\n     * @param bindAddress   address to bind to on the server:\r\n     *                      <ul>\r\n     *                      <li>\"\" means that connections are to be accepted on all protocol families\r\n     *                      supported by the SSH implementation</li>\r\n     *                      <li>\"0.0.0.0\" means to listen on all IPv4 addresses</li>\r\n     *                      <li>\"::\" means to listen on all IPv6 addresses</li>\r\n     *                      <li>\"localhost\" means to listen on all protocol families supported by the SSH\r\n     *                      implementation on loopback addresses only, [RFC3330] and RFC3513]</li>\r\n     *                      <li>\"127.0.0.1\" and \"::1\" indicate listening on the loopback interfaces for\r\n     *                      IPv4 and IPv6 respectively</li>\r\n     *                      </ul>\r\n     * @param bindPort      port number to bind on the server (must be &gt; 0)\r\n     * @param targetAddress the target address (IP or hostname)\r\n     * @param targetPort    the target port\r\n     * @throws IOException\r\n     */\r\n    public synchronized void requestRemotePortForwarding(String bindAddress, int bindPort, String targetAddress,\r\n                                                         int targetPort) throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"You need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"The connection is not authenticated.\");\r\n\r\n        if ((bindAddress == null) || (targetAddress == null) || (bindPort <= 0) || (targetPort <= 0))\r\n            throw new IllegalArgumentException();\r\n\r\n        cm.requestGlobalForward(bindAddress, bindPort, targetAddress, targetPort);\r\n    }\r\n\r\n    /**\r\n     * Cancel an earlier requested remote port forwarding.\r\n     * Currently active forwardings will not be affected (e.g., disrupted).\r\n     * Note that further connection forwarding requests may be received until\r\n     * this method has returned.\r\n     *\r\n     * @param bindPort the allocated port number on the server\r\n     * @throws IOException if the remote side refuses the cancel request or another low\r\n     *                     level error occurs (e.g., the underlying connection is closed)\r\n     */\r\n    public synchronized void cancelRemotePortForwarding(int bindPort) throws IOException {\r\n        if (tm == null)\r\n            throw new IllegalStateException(\"You need to establish a connection first.\");\r\n\r\n        if (!authenticated)\r\n            throw new IllegalStateException(\"The connection is not authenticated.\");\r\n\r\n        cm.requestCancelGlobalForward(bindPort);\r\n    }\r\n\r\n    /**\r\n     * Provide your own instance of SecureRandom. Can be used, e.g., if you\r\n     * want to seed the used SecureRandom generator manually.\r\n     * <p>\r\n     * The SecureRandom instance is used during key exchanges, public key authentication,\r\n     * x11 cookie generation and the like.\r\n     *\r\n     * @param rnd a SecureRandom instance\r\n     */\r\n    public synchronized void setSecureRandom(SecureRandom rnd) {\r\n        if (rnd == null)\r\n            throw new IllegalArgumentException();\r\n\r\n        this.generator = rnd;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/ConnectionInfo.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * In most cases you probably do not need the information contained in here.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ConnectionInfo.java,v 1.3 2005/08/24 17:54:10 cplattne Exp $\r\n */\r\npublic class ConnectionInfo {\r\n    /**\r\n     * The used key exchange (KEX) algorithm in the latest key exchange.\r\n     */\r\n    public String keyExchangeAlgorithm;\r\n\r\n    /**\r\n     * The currently used crypto algorithm for packets from to the client to the\r\n     * server.\r\n     */\r\n    public String clientToServerCryptoAlgorithm;\r\n    /**\r\n     * The currently used crypto algorithm for packets from to the server to the\r\n     * client.\r\n     */\r\n    public String serverToClientCryptoAlgorithm;\r\n\r\n    /**\r\n     * The currently used MAC algorithm for packets from to the client to the\r\n     * server.\r\n     */\r\n    public String clientToServerMACAlgorithm;\r\n    /**\r\n     * The currently used MAC algorithm for packets from to the server to the\r\n     * client.\r\n     */\r\n    public String serverToClientMACAlgorithm;\r\n\r\n    /**\r\n     * The type of the server host key (currently either \"ssh-dss\" or\r\n     * \"ssh-rsa\").\r\n     */\r\n    public String serverHostKeyAlgorithm;\r\n    /**\r\n     * The server host key that was sent during the latest key exchange.\r\n     */\r\n    public byte[] serverHostKey;\r\n\r\n    /**\r\n     * Number of kex exchanges performed on this connection so far.\r\n     */\r\n    public int keyExchangeCounter = 0;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/ConnectionMonitor.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>ConnectionMonitor</code> is used to get notified when the\r\n * underlying socket of a connection is closed.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ConnectionMonitor.java,v 1.3 2006/08/11 17:44:37 cplattne Exp $\r\n */\r\n\r\npublic interface ConnectionMonitor {\r\n    /**\r\n     * This method is called after the connection's underlying\r\n     * socket has been closed. E.g., due to the {@link Connection#close()} request of the\r\n     * user, if the peer closed the connection, due to a fatal error during connect()\r\n     * (also if the socket cannot be established) or if a fatal error occured on\r\n     * an established connection.\r\n     * <p>\r\n     * This is an experimental feature.\r\n     * <p>\r\n     * You MUST NOT make any assumption about the thread that invokes this method.\r\n     * <p>\r\n     * <b>Please note: if the connection is not connected (e.g., there was no successful\r\n     * connect() call), then the invocation of {@link Connection#close()} will NOT trigger\r\n     * this method.</b>\r\n     *\r\n     * @param reason Includes an indication why the socket was closed.\r\n     * @see Connection#addConnectionMonitor(ConnectionMonitor)\r\n     */\r\n    public void connectionLost(Throwable reason);\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/DHGexParameters.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>DHGexParameters</code> object can be used to specify parameters for\r\n * the diffie-hellman group exchange.\r\n * <p>\r\n * Depending on which constructor is used, either the use of a\r\n * <code>SSH_MSG_KEX_DH_GEX_REQUEST</code> or <code>SSH_MSG_KEX_DH_GEX_REQUEST_OLD</code>\r\n * can be forced.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DHGexParameters.java,v 1.3 2006/09/20 12:51:37 cplattne Exp $\r\n * @see Connection#setDHGexParameters(DHGexParameters)\r\n */\r\n\r\npublic class DHGexParameters {\r\n    private static final int MIN_ALLOWED = 1024;\r\n    private static final int MAX_ALLOWED = 8192;\r\n    private final int min_group_len;\r\n    private final int pref_group_len;\r\n    private final int max_group_len;\r\n\r\n    /**\r\n     * Same as calling {@link #DHGexParameters(int, int, int) DHGexParameters(1024, 1024, 4096)}.\r\n     * This is also the default used by the Connection class.\r\n     */\r\n    public DHGexParameters() {\r\n        this(1024, 1024, 4096);\r\n    }\r\n\r\n    /**\r\n     * This constructor can be used to force the sending of a\r\n     * <code>SSH_MSG_KEX_DH_GEX_REQUEST_OLD</code> request.\r\n     * Internally, the minimum and maximum group lengths will\r\n     * be set to zero.\r\n     *\r\n     * @param pref_group_len has to be &gt= 1024 and &lt;= 8192\r\n     */\r\n    public DHGexParameters(int pref_group_len) {\r\n        if ((pref_group_len < MIN_ALLOWED) || (pref_group_len > MAX_ALLOWED))\r\n            throw new IllegalArgumentException(\"pref_group_len out of range!\");\r\n\r\n        this.pref_group_len = pref_group_len;\r\n        this.min_group_len = 0;\r\n        this.max_group_len = 0;\r\n    }\r\n\r\n    /**\r\n     * This constructor can be used to force the sending of a\r\n     * <code>SSH_MSG_KEX_DH_GEX_REQUEST</code> request.\r\n     * <p>\r\n     * Note: older OpenSSH servers don't understand this request, in which\r\n     * case you should use the {@link #DHGexParameters(int)} constructor.\r\n     * <p>\r\n     * All values have to be &gt= 1024 and &lt;= 8192. Furthermore,\r\n     * min_group_len &lt;= pref_group_len &lt;= max_group_len.\r\n     *\r\n     * @param min_group_len\r\n     * @param pref_group_len\r\n     * @param max_group_len\r\n     */\r\n    public DHGexParameters(int min_group_len, int pref_group_len, int max_group_len) {\r\n        if ((min_group_len < MIN_ALLOWED) || (min_group_len > MAX_ALLOWED))\r\n            throw new IllegalArgumentException(\"min_group_len out of range!\");\r\n\r\n        if ((pref_group_len < MIN_ALLOWED) || (pref_group_len > MAX_ALLOWED))\r\n            throw new IllegalArgumentException(\"pref_group_len out of range!\");\r\n\r\n        if ((max_group_len < MIN_ALLOWED) || (max_group_len > MAX_ALLOWED))\r\n            throw new IllegalArgumentException(\"max_group_len out of range!\");\r\n\r\n        if ((pref_group_len < min_group_len) || (pref_group_len > max_group_len))\r\n            throw new IllegalArgumentException(\"pref_group_len is incompatible with min and max!\");\r\n\r\n        if (max_group_len < min_group_len)\r\n            throw new IllegalArgumentException(\"max_group_len must not be smaller than min_group_len!\");\r\n\r\n        this.min_group_len = min_group_len;\r\n        this.pref_group_len = pref_group_len;\r\n        this.max_group_len = max_group_len;\r\n    }\r\n\r\n    /**\r\n     * Get the maximum group length.\r\n     *\r\n     * @return the maximum group length, may be <code>zero</code> if\r\n     * SSH_MSG_KEX_DH_GEX_REQUEST_OLD should be requested\r\n     */\r\n    public int getMax_group_len() {\r\n        return max_group_len;\r\n    }\r\n\r\n    /**\r\n     * Get the minimum group length.\r\n     *\r\n     * @return minimum group length, may be <code>zero</code> if\r\n     * SSH_MSG_KEX_DH_GEX_REQUEST_OLD should be requested\r\n     */\r\n    public int getMin_group_len() {\r\n        return min_group_len;\r\n    }\r\n\r\n    /**\r\n     * Get the preferred group length.\r\n     *\r\n     * @return the preferred group length\r\n     */\r\n    public int getPref_group_len() {\r\n        return pref_group_len;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/HTTPProxyData.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>HTTPProxyData</code> object is used to specify the needed connection data\r\n * to connect through a HTTP proxy.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: HTTPProxyData.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n * @see Connection#setProxyData(ProxyData)\r\n */\r\n\r\npublic class HTTPProxyData implements ProxyData {\r\n    public final String proxyHost;\r\n    public final int proxyPort;\r\n    public final String proxyUser;\r\n    public final String proxyPass;\r\n    public final String[] requestHeaderLines;\r\n\r\n    /**\r\n     * Same as calling {@link #HTTPProxyData(String, int, String, String) HTTPProxyData(proxyHost, proxyPort, <code>null</code>, <code>null</code>)}\r\n     *\r\n     * @param proxyHost Proxy hostname.\r\n     * @param proxyPort Proxy port.\r\n     */\r\n    public HTTPProxyData(String proxyHost, int proxyPort) {\r\n        this(proxyHost, proxyPort, null, null);\r\n    }\r\n\r\n    /**\r\n     * Same as calling {@link #HTTPProxyData(String, int, String, String, String[]) HTTPProxyData(proxyHost, proxyPort, <code>null</code>, <code>null</code>, <code>null</code>)}\r\n     *\r\n     * @param proxyHost Proxy hostname.\r\n     * @param proxyPort Proxy port.\r\n     * @param proxyUser Username for basic authentication (<code>null</code> if no authentication is needed).\r\n     * @param proxyPass Password for basic authentication (<code>null</code> if no authentication is needed).\r\n     */\r\n    public HTTPProxyData(String proxyHost, int proxyPort, String proxyUser, String proxyPass) {\r\n        this(proxyHost, proxyPort, proxyUser, proxyPass, null);\r\n    }\r\n\r\n    /**\r\n     * Connection data for a HTTP proxy. It is possible to specify a username and password\r\n     * if the proxy requires basic authentication. Also, additional request header lines can\r\n     * be specified (e.g., \"User-Agent: CERN-LineMode/2.15 libwww/2.17b3\").\r\n     * <p>\r\n     * Please note: if you want to use basic authentication, then both <code>proxyUser</code>\r\n     * and <code>proxyPass</code> must be non-null.\r\n     * <p>\r\n     * Here is an example:\r\n     * <p>\r\n     * <code>\r\n     * new HTTPProxyData(\"192.168.1.1\", \"3128\", \"proxyuser\", \"secret\", new String[] {\"User-Agent: GanymedBasedClient/1.0\", \"X-My-Proxy-Option: something\"});\r\n     * </code>\r\n     *\r\n     * @param proxyHost          Proxy hostname.\r\n     * @param proxyPort          Proxy port.\r\n     * @param proxyUser          Username for basic authentication (<code>null</code> if no authentication is needed).\r\n     * @param proxyPass          Password for basic authentication (<code>null</code> if no authentication is needed).\r\n     * @param requestHeaderLines An array with additional request header lines (without end-of-line markers)\r\n     *                           that have to be sent to the server. May be <code>null</code>.\r\n     */\r\n\r\n    public HTTPProxyData(String proxyHost, int proxyPort, String proxyUser, String proxyPass,\r\n                         String[] requestHeaderLines) {\r\n        if (proxyHost == null)\r\n            throw new IllegalArgumentException(\"proxyHost must be non-null\");\r\n\r\n        if (proxyPort < 0)\r\n            throw new IllegalArgumentException(\"proxyPort must be non-negative\");\r\n\r\n        this.proxyHost = proxyHost;\r\n        this.proxyPort = proxyPort;\r\n        this.proxyUser = proxyUser;\r\n        this.proxyPass = proxyPass;\r\n        this.requestHeaderLines = requestHeaderLines;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/HTTPProxyException.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * May be thrown upon connect() if a HTTP proxy is being used.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: HTTPProxyException.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n * @see Connection#connect()\r\n * @see Connection#setProxyData(ProxyData)\r\n */\r\n\r\npublic class HTTPProxyException extends IOException {\r\n    private static final long serialVersionUID = 2241537397104426186L;\r\n\r\n    public final String httpResponse;\r\n    public final int httpErrorCode;\r\n\r\n    public HTTPProxyException(String httpResponse, int httpErrorCode) {\r\n        super(\"HTTP Proxy Error (\" + httpErrorCode + \" \" + httpResponse + \")\");\r\n        this.httpResponse = httpResponse;\r\n        this.httpErrorCode = httpErrorCode;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/InteractiveCallback.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * An <code>InteractiveCallback</code> is used to respond to challenges sent\r\n * by the server if authentication mode \"keyboard-interactive\" is selected.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: InteractiveCallback.java,v 1.3 2006/02/13 21:19:25 cplattne Exp $\r\n * @see Connection#authenticateWithKeyboardInteractive(String,\r\n * String[], InteractiveCallback)\r\n */\r\n\r\npublic interface InteractiveCallback {\r\n    /**\r\n     * This callback interface is used during a \"keyboard-interactive\"\r\n     * authentication. Every time the server sends a set of challenges (however,\r\n     * most often just one challenge at a time), this callback function will be\r\n     * called to give your application a chance to talk to the user and to\r\n     * determine the response(s).\r\n     * <p>\r\n     * Some copy-paste information from the standard: a command line interface\r\n     * (CLI) client SHOULD print the name and instruction (if non-empty), adding\r\n     * newlines. Then for each prompt in turn, the client SHOULD display the\r\n     * prompt and read the user input. The name and instruction fields MAY be\r\n     * empty strings, the client MUST be prepared to handle this correctly. The\r\n     * prompt field(s) MUST NOT be empty strings.\r\n     * <p>\r\n     * Please refer to draft-ietf-secsh-auth-kbdinteract-XX.txt for the details.\r\n     * <p>\r\n     * Note: clients SHOULD use control character filtering as discussed in\r\n     * [draft-ietf-secsh-architecture-XX.txt] to avoid attacks by including\r\n     * terminal control characters in the fields to be displayed.\r\n     *\r\n     * @param name        the name String sent by the server.\r\n     * @param instruction the instruction String sent by the server.\r\n     * @param numPrompts  number of prompts - may be zero (in this case, you should just\r\n     *                    return a String array of length zero).\r\n     * @param prompt      an array (length <code>numPrompts</code>) of Strings\r\n     * @param echo        an array (length <code>numPrompts</code>) of booleans. For\r\n     *                    each prompt, the corresponding echo field indicates whether or\r\n     *                    not the user input should be echoed as characters are typed.\r\n     * @return an array of reponses - the array size must match the parameter\r\n     * <code>numPrompts</code>.\r\n     */\r\n    public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) throws Exception;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/KnownHosts.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.crypto.Base64;\r\nimport ch.ethz.ssh2.crypto.digest.Digest;\r\nimport ch.ethz.ssh2.crypto.digest.HMAC;\r\nimport ch.ethz.ssh2.crypto.digest.MD5;\r\nimport ch.ethz.ssh2.crypto.digest.SHA1;\r\nimport ch.ethz.ssh2.signature.DSAPublicKey;\r\nimport ch.ethz.ssh2.signature.DSASHA1Verify;\r\nimport ch.ethz.ssh2.signature.RSAPublicKey;\r\nimport ch.ethz.ssh2.signature.RSASHA1Verify;\r\n\r\nimport java.io.*;\r\nimport java.net.InetAddress;\r\nimport java.net.UnknownHostException;\r\nimport java.security.SecureRandom;\r\nimport java.util.Iterator;\r\nimport java.util.LinkedList;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * The <code>KnownHosts</code> class is a handy tool to verify received server hostkeys\r\n * based on the information in <code>known_hosts</code> files (the ones used by OpenSSH).\r\n * <p>\r\n * It offers basically an in-memory database for known_hosts entries, as well as some\r\n * helper functions. Entries from a <code>known_hosts</code> file can be loaded at construction time.\r\n * It is also possible to add more keys later (e.g., one can parse different\r\n * <code>known_hosts<code> files).\r\n * <p>\r\n * It is a thread safe implementation, therefore, you need only to instantiate one\r\n * <code>KnownHosts</code> for your whole application.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: KnownHosts.java,v 1.5 2006/07/30 21:59:29 cplattne Exp $\r\n */\r\n\r\npublic class KnownHosts {\r\n    public static final int HOSTKEY_IS_OK = 0;\r\n    public static final int HOSTKEY_IS_NEW = 1;\r\n    public static final int HOSTKEY_HAS_CHANGED = 2;\r\n    private LinkedList publicKeys = new LinkedList();\r\n\r\n    public KnownHosts() {\r\n    }\r\n\r\n    public KnownHosts(char[] knownHostsData) throws IOException {\r\n        initialize(knownHostsData);\r\n    }\r\n\r\n    public KnownHosts(File knownHosts) throws IOException {\r\n        initialize(knownHosts);\r\n    }\r\n\r\n    /**\r\n     * Generate the hashed representation of the given hostname. Useful for adding entries\r\n     * with hashed hostnames to a known_hosts file. (see -H option of OpenSSH key-gen).\r\n     *\r\n     * @param hostname\r\n     * @return the hashed representation, e.g., \"|1|cDhrv7zwEUV3k71CEPHnhHZezhA=|Xo+2y6rUXo2OIWRAYhBOIijbJMA=\"\r\n     */\r\n    public static final String createHashedHostname(String hostname) {\r\n        SHA1 sha1 = new SHA1();\r\n\r\n        byte[] salt = new byte[sha1.getDigestLength()];\r\n\r\n        new SecureRandom().nextBytes(salt);\r\n\r\n        byte[] hash = hmacSha1Hash(salt, hostname);\r\n\r\n        String base64_salt = new String(Base64.encode(salt));\r\n        String base64_hash = new String(Base64.encode(hash));\r\n\r\n        return new String(\"|1|\" + base64_salt + \"|\" + base64_hash);\r\n    }\r\n\r\n    private static final byte[] hmacSha1Hash(byte[] salt, String hostname) {\r\n        SHA1 sha1 = new SHA1();\r\n\r\n        if (salt.length != sha1.getDigestLength())\r\n            throw new IllegalArgumentException(\"Salt has wrong length (\" + salt.length + \")\");\r\n\r\n        HMAC hmac = new HMAC(sha1, salt, salt.length);\r\n\r\n        hmac.update(hostname.getBytes());\r\n\r\n        byte[] dig = new byte[hmac.getDigestLength()];\r\n\r\n        hmac.digest(dig);\r\n\r\n        return dig;\r\n    }\r\n\r\n    /**\r\n     * Adds a single public key entry to the a known_hosts file.\r\n     * This method is designed to be used in a {@link ServerHostKeyVerifier}.\r\n     *\r\n     * @param knownHosts             the file where the publickey entry will be appended.\r\n     * @param hostnames              a list of hostname patterns - at least one most be specified. Check out the\r\n     *                               OpenSSH sshd man page for a description of the pattern matching algorithm.\r\n     * @param serverHostKeyAlgorithm as passed to the {@link ServerHostKeyVerifier}.\r\n     * @param serverHostKey          as passed to the {@link ServerHostKeyVerifier}.\r\n     * @throws IOException\r\n     */\r\n    public final static void addHostkeyToFile(File knownHosts, String[] hostnames, String serverHostKeyAlgorithm,\r\n                                              byte[] serverHostKey) throws IOException {\r\n        if ((hostnames == null) || (hostnames.length == 0))\r\n            throw new IllegalArgumentException(\"Need at least one hostname specification\");\r\n\r\n        if ((serverHostKeyAlgorithm == null) || (serverHostKey == null))\r\n            throw new IllegalArgumentException();\r\n\r\n        CharArrayWriter writer = new CharArrayWriter();\r\n\r\n        for (int i = 0; i < hostnames.length; i++) {\r\n            if (i != 0)\r\n                writer.write(',');\r\n            writer.write(hostnames[i]);\r\n        }\r\n\r\n        writer.write(' ');\r\n        writer.write(serverHostKeyAlgorithm);\r\n        writer.write(' ');\r\n        writer.write(Base64.encode(serverHostKey));\r\n        writer.write(\"\\n\");\r\n\r\n        char[] entry = writer.toCharArray();\r\n\r\n        RandomAccessFile raf = new RandomAccessFile(knownHosts, \"rw\");\r\n\r\n        long len = raf.length();\r\n\r\n        if (len > 0) {\r\n            raf.seek(len - 1);\r\n            int last = raf.read();\r\n            if (last != '\\n')\r\n                raf.write('\\n');\r\n        }\r\n\r\n        raf.write(new String(entry).getBytes());\r\n        raf.close();\r\n    }\r\n\r\n    /**\r\n     * Generates a \"raw\" fingerprint of a hostkey.\r\n     *\r\n     * @param type    either \"md5\" or \"sha1\"\r\n     * @param keyType either \"ssh-rsa\" or \"ssh-dss\"\r\n     * @param hostkey the hostkey\r\n     * @return the raw fingerprint\r\n     */\r\n    static final private byte[] rawFingerPrint(String type, String keyType, byte[] hostkey) {\r\n        Digest dig = null;\r\n\r\n        if (\"md5\".equals(type)) {\r\n            dig = new MD5();\r\n        } else if (\"sha1\".equals(type)) {\r\n            dig = new SHA1();\r\n        } else\r\n            throw new IllegalArgumentException(\"Unknown hash type \" + type);\r\n\r\n        if (\"ssh-rsa\".equals(keyType)) {\r\n        } else if (\"ssh-dss\".equals(keyType)) {\r\n        } else\r\n            throw new IllegalArgumentException(\"Unknown key type \" + keyType);\r\n\r\n        if (hostkey == null)\r\n            throw new IllegalArgumentException(\"hostkey is null\");\r\n\r\n        dig.update(hostkey);\r\n        byte[] res = new byte[dig.getDigestLength()];\r\n        dig.digest(res);\r\n        return res;\r\n    }\r\n\r\n    /**\r\n     * Convert a raw fingerprint to hex representation (XX:YY:ZZ...).\r\n     *\r\n     * @param fingerprint raw fingerprint\r\n     * @return the hex representation\r\n     */\r\n    static final private String rawToHexFingerprint(byte[] fingerprint) {\r\n        final char[] alpha = \"0123456789abcdef\".toCharArray();\r\n\r\n        StringBuffer sb = new StringBuffer();\r\n\r\n        for (int i = 0; i < fingerprint.length; i++) {\r\n            if (i != 0)\r\n                sb.append(':');\r\n            int b = fingerprint[i] & 0xff;\r\n            sb.append(alpha[b >> 4]);\r\n            sb.append(alpha[b & 15]);\r\n        }\r\n\r\n        return sb.toString();\r\n    }\r\n\r\n    /**\r\n     * Convert a raw fingerprint to bubblebabble representation.\r\n     *\r\n     * @param raw raw fingerprint\r\n     * @return the bubblebabble representation\r\n     */\r\n    static final private String rawToBubblebabbleFingerprint(byte[] raw) {\r\n        final char[] v = \"aeiouy\".toCharArray();\r\n        final char[] c = \"bcdfghklmnprstvzx\".toCharArray();\r\n\r\n        StringBuffer sb = new StringBuffer();\r\n\r\n        int seed = 1;\r\n\r\n        int rounds = (raw.length / 2) + 1;\r\n\r\n        sb.append('x');\r\n\r\n        for (int i = 0; i < rounds; i++) {\r\n            if (((i + 1) < rounds) || ((raw.length) % 2 != 0)) {\r\n                sb.append(v[(((raw[2 * i] >> 6) & 3) + seed) % 6]);\r\n                sb.append(c[(raw[2 * i] >> 2) & 15]);\r\n                sb.append(v[((raw[2 * i] & 3) + (seed / 6)) % 6]);\r\n\r\n                if ((i + 1) < rounds) {\r\n                    sb.append(c[(((raw[(2 * i) + 1])) >> 4) & 15]);\r\n                    sb.append('-');\r\n                    sb.append(c[(((raw[(2 * i) + 1]))) & 15]);\r\n                    // As long as seed >= 0, seed will be >= 0 afterwards\r\n                    seed = ((seed * 5) + (((raw[2 * i] & 0xff) * 7) + (raw[(2 * i) + 1] & 0xff))) % 36;\r\n                }\r\n            } else {\r\n                sb.append(v[seed % 6]); // seed >= 0, therefore index positive\r\n                sb.append('x');\r\n                sb.append(v[seed / 6]);\r\n            }\r\n        }\r\n\r\n        sb.append('x');\r\n\r\n        return sb.toString();\r\n    }\r\n\r\n    /**\r\n     * Convert a ssh2 key-blob into a human readable hex fingerprint.\r\n     * Generated fingerprints are identical to those generated by OpenSSH.\r\n     * <p>\r\n     * Example fingerprint: d0:cb:76:19:99:5a:03:fc:73:10:70:93:f2:44:63:47.\r\n     *\r\n     * @param keytype   either \"ssh-rsa\" or \"ssh-dss\"\r\n     * @param publickey key blob\r\n     * @return Hex fingerprint\r\n     */\r\n    public final static String createHexFingerprint(String keytype, byte[] publickey) {\r\n        byte[] raw = rawFingerPrint(\"md5\", keytype, publickey);\r\n        return rawToHexFingerprint(raw);\r\n    }\r\n\r\n    /**\r\n     * Convert a ssh2 key-blob into a human readable bubblebabble fingerprint.\r\n     * The used bubblebabble algorithm (taken from OpenSSH) generates fingerprints\r\n     * that are easier to remember for humans.\r\n     * <p>\r\n     * Example fingerprint: xofoc-bubuz-cazin-zufyl-pivuk-biduk-tacib-pybur-gonar-hotat-lyxux.\r\n     *\r\n     * @param keytype   either \"ssh-rsa\" or \"ssh-dss\"\r\n     * @param publickey key data\r\n     * @return Bubblebabble fingerprint\r\n     */\r\n    public final static String createBubblebabbleFingerprint(String keytype, byte[] publickey) {\r\n        byte[] raw = rawFingerPrint(\"sha1\", keytype, publickey);\r\n        return rawToBubblebabbleFingerprint(raw);\r\n    }\r\n\r\n    /**\r\n     * Adds a single public key entry to the database. Note: this will NOT add the public key\r\n     * to any physical file (e.g., \"~/.ssh/known_hosts\") - use <code>addHostkeyToFile()</code> for that purpose.\r\n     * This method is designed to be used in a {@link ServerHostKeyVerifier}.\r\n     *\r\n     * @param hostnames              a list of hostname patterns - at least one most be specified. Check out the\r\n     *                               OpenSSH sshd man page for a description of the pattern matching algorithm.\r\n     * @param serverHostKeyAlgorithm as passed to the {@link ServerHostKeyVerifier}.\r\n     * @param serverHostKey          as passed to the {@link ServerHostKeyVerifier}.\r\n     * @throws IOException\r\n     */\r\n    public void addHostkey(String hostnames[], String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException {\r\n        if (hostnames == null)\r\n            throw new IllegalArgumentException(\"hostnames may not be null\");\r\n\r\n        if (\"ssh-rsa\".equals(serverHostKeyAlgorithm)) {\r\n            RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey);\r\n\r\n            synchronized (publicKeys) {\r\n                publicKeys.add(new KnownHostsEntry(hostnames, rpk));\r\n            }\r\n        } else if (\"ssh-dss\".equals(serverHostKeyAlgorithm)) {\r\n            DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);\r\n\r\n            synchronized (publicKeys) {\r\n                publicKeys.add(new KnownHostsEntry(hostnames, dpk));\r\n            }\r\n        } else\r\n            throw new IOException(\"Unknwon host key type (\" + serverHostKeyAlgorithm + \")\");\r\n    }\r\n\r\n    /**\r\n     * Parses the given known_hosts data and adds entries to the database.\r\n     *\r\n     * @param knownHostsData\r\n     * @throws IOException\r\n     */\r\n    public void addHostkeys(char[] knownHostsData) throws IOException {\r\n        initialize(knownHostsData);\r\n    }\r\n\r\n    /**\r\n     * Parses the given known_hosts file and adds entries to the database.\r\n     *\r\n     * @param knownHosts\r\n     * @throws IOException\r\n     */\r\n    public void addHostkeys(File knownHosts) throws IOException {\r\n        initialize(knownHosts);\r\n    }\r\n\r\n    private final boolean checkHashed(String entry, String hostname) {\r\n        if (entry.startsWith(\"|1|\") == false)\r\n            return false;\r\n\r\n        int delim_idx = entry.indexOf('|', 3);\r\n\r\n        if (delim_idx == -1)\r\n            return false;\r\n\r\n        String salt_base64 = entry.substring(3, delim_idx);\r\n        String hash_base64 = entry.substring(delim_idx + 1);\r\n\r\n        byte[] salt = null;\r\n        byte[] hash = null;\r\n\r\n        try {\r\n            salt = Base64.decode(salt_base64.toCharArray());\r\n            hash = Base64.decode(hash_base64.toCharArray());\r\n        } catch (IOException e) {\r\n            return false;\r\n        }\r\n\r\n        SHA1 sha1 = new SHA1();\r\n\r\n        if (salt.length != sha1.getDigestLength())\r\n            return false;\r\n\r\n        byte[] dig = hmacSha1Hash(salt, hostname);\r\n\r\n        for (int i = 0; i < dig.length; i++)\r\n            if (dig[i] != hash[i])\r\n                return false;\r\n\r\n        return true;\r\n    }\r\n\r\n    private int checkKey(String remoteHostname, Object remoteKey) {\r\n        int result = HOSTKEY_IS_NEW;\r\n\r\n        synchronized (publicKeys) {\r\n            Iterator i = publicKeys.iterator();\r\n\r\n            while (i.hasNext()) {\r\n                KnownHostsEntry ke = (KnownHostsEntry) i.next();\r\n\r\n                if (hostnameMatches(ke.patterns, remoteHostname) == false)\r\n                    continue;\r\n\r\n                boolean res = matchKeys(ke.key, remoteKey);\r\n\r\n                if (res == true)\r\n                    return HOSTKEY_IS_OK;\r\n\r\n                result = HOSTKEY_HAS_CHANGED;\r\n            }\r\n        }\r\n        return result;\r\n    }\r\n\r\n    private Vector getAllKeys(String hostname) {\r\n        Vector keys = new Vector();\r\n\r\n        synchronized (publicKeys) {\r\n            Iterator i = publicKeys.iterator();\r\n\r\n            while (i.hasNext()) {\r\n                KnownHostsEntry ke = (KnownHostsEntry) i.next();\r\n\r\n                if (hostnameMatches(ke.patterns, hostname) == false)\r\n                    continue;\r\n\r\n                keys.addElement(ke.key);\r\n            }\r\n        }\r\n\r\n        return keys;\r\n    }\r\n\r\n    /**\r\n     * Try to find the preferred order of hostkey algorithms for the given hostname.\r\n     * Based on the type of hostkey that is present in the internal database\r\n     * (i.e., either <code>ssh-rsa</code> or <code>ssh-dss</code>)\r\n     * an ordered list of hostkey algorithms is returned which can be passed\r\n     * to <code>Connection.setServerHostKeyAlgorithms</code>.\r\n     *\r\n     * @param hostname\r\n     * @return <code>null</code> if no key for the given hostname is present or\r\n     * there are keys of multiple types present for the given hostname. Otherwise,\r\n     * an array with hostkey algorithms is returned (i.e., an array of length 2).\r\n     */\r\n    public String[] getPreferredServerHostkeyAlgorithmOrder(String hostname) {\r\n        String[] algos = recommendHostkeyAlgorithms(hostname);\r\n\r\n        if (algos != null)\r\n            return algos;\r\n\r\n        InetAddress[] ipAdresses = null;\r\n\r\n        try {\r\n            ipAdresses = InetAddress.getAllByName(hostname);\r\n        } catch (UnknownHostException e) {\r\n            return null;\r\n        }\r\n\r\n        for (int i = 0; i < ipAdresses.length; i++) {\r\n            algos = recommendHostkeyAlgorithms(ipAdresses[i].getHostAddress());\r\n\r\n            if (algos != null)\r\n                return algos;\r\n        }\r\n\r\n        return null;\r\n    }\r\n\r\n    private final boolean hostnameMatches(String[] hostpatterns, String hostname) {\r\n        boolean isMatch = false;\r\n        boolean negate = false;\r\n\r\n        hostname = hostname.toLowerCase();\r\n\r\n        for (int k = 0; k < hostpatterns.length; k++) {\r\n            if (hostpatterns[k] == null)\r\n                continue;\r\n\r\n            String pattern = null;\r\n\r\n\t\t\t/* In contrast to OpenSSH we also allow negated hash entries (as well as hashed\r\n             * entries in lines with multiple entries).\r\n\t\t\t */\r\n\r\n            if ((hostpatterns[k].length() > 0) && (hostpatterns[k].charAt(0) == '!')) {\r\n                pattern = hostpatterns[k].substring(1);\r\n                negate = true;\r\n            } else {\r\n                pattern = hostpatterns[k];\r\n                negate = false;\r\n            }\r\n\r\n\t\t\t/* Optimize, no need to check this entry */\r\n\r\n            if ((isMatch) && (negate == false))\r\n                continue;\r\n\r\n\t\t\t/* Now compare */\r\n\r\n            if (pattern.charAt(0) == '|') {\r\n                if (checkHashed(pattern, hostname)) {\r\n                    if (negate)\r\n                        return false;\r\n                    isMatch = true;\r\n                }\r\n            } else {\r\n                pattern = pattern.toLowerCase();\r\n\r\n                if ((pattern.indexOf('?') != -1) || (pattern.indexOf('*') != -1)) {\r\n                    if (pseudoRegex(pattern.toCharArray(), 0, hostname.toCharArray(), 0)) {\r\n                        if (negate)\r\n                            return false;\r\n                        isMatch = true;\r\n                    }\r\n                } else if (pattern.compareTo(hostname) == 0) {\r\n                    if (negate)\r\n                        return false;\r\n                    isMatch = true;\r\n                }\r\n            }\r\n        }\r\n\r\n        return isMatch;\r\n    }\r\n\r\n    private void initialize(char[] knownHostsData) throws IOException {\r\n        BufferedReader br = new BufferedReader(new CharArrayReader(knownHostsData));\r\n\r\n        while (true) {\r\n            String line = br.readLine();\r\n\r\n            if (line == null)\r\n                break;\r\n\r\n            line = line.trim();\r\n\r\n            if (line.startsWith(\"#\"))\r\n                continue;\r\n\r\n            String[] arr = line.split(\" \");\r\n\r\n            if (arr.length >= 3) {\r\n                if ((arr[1].compareTo(\"ssh-rsa\") == 0) || (arr[1].compareTo(\"ssh-dss\") == 0)) {\r\n                    String[] hostnames = arr[0].split(\",\");\r\n\r\n                    byte[] msg = Base64.decode(arr[2].toCharArray());\r\n\r\n                    addHostkey(hostnames, arr[1], msg);\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    private void initialize(File knownHosts) throws IOException {\r\n        char[] buff = new char[512];\r\n\r\n        CharArrayWriter cw = new CharArrayWriter();\r\n\r\n        knownHosts.createNewFile();\r\n\r\n        FileReader fr = new FileReader(knownHosts);\r\n\r\n        while (true) {\r\n            int len = fr.read(buff);\r\n            if (len < 0)\r\n                break;\r\n            cw.write(buff, 0, len);\r\n        }\r\n\r\n        fr.close();\r\n\r\n        initialize(cw.toCharArray());\r\n    }\r\n\r\n    private final boolean matchKeys(Object key1, Object key2) {\r\n        if ((key1 instanceof RSAPublicKey) && (key2 instanceof RSAPublicKey)) {\r\n            RSAPublicKey savedRSAKey = (RSAPublicKey) key1;\r\n            RSAPublicKey remoteRSAKey = (RSAPublicKey) key2;\r\n\r\n            if (savedRSAKey.getE().equals(remoteRSAKey.getE()) == false)\r\n                return false;\r\n\r\n            if (savedRSAKey.getN().equals(remoteRSAKey.getN()) == false)\r\n                return false;\r\n\r\n            return true;\r\n        }\r\n\r\n        if ((key1 instanceof DSAPublicKey) && (key2 instanceof DSAPublicKey)) {\r\n            DSAPublicKey savedDSAKey = (DSAPublicKey) key1;\r\n            DSAPublicKey remoteDSAKey = (DSAPublicKey) key2;\r\n\r\n            if (savedDSAKey.getG().equals(remoteDSAKey.getG()) == false)\r\n                return false;\r\n\r\n            if (savedDSAKey.getP().equals(remoteDSAKey.getP()) == false)\r\n                return false;\r\n\r\n            if (savedDSAKey.getQ().equals(remoteDSAKey.getQ()) == false)\r\n                return false;\r\n\r\n            if (savedDSAKey.getY().equals(remoteDSAKey.getY()) == false)\r\n                return false;\r\n\r\n            return true;\r\n        }\r\n\r\n        return false;\r\n    }\r\n\r\n    private final boolean pseudoRegex(char[] pattern, int i, char[] match, int j) {\r\n\t\t/* This matching logic is equivalent to the one present in OpenSSH 4.1 */\r\n\r\n        while (true) {\r\n\t\t\t/* Are we at the end of the pattern? */\r\n\r\n            if (pattern.length == i)\r\n                return (match.length == j);\r\n\r\n            if (pattern[i] == '*') {\r\n                i++;\r\n\r\n                if (pattern.length == i)\r\n                    return true;\r\n\r\n                if ((pattern[i] != '*') && (pattern[i] != '?')) {\r\n                    while (true) {\r\n                        if ((pattern[i] == match[j]) && pseudoRegex(pattern, i + 1, match, j + 1))\r\n                            return true;\r\n                        j++;\r\n                        if (match.length == j)\r\n                            return false;\r\n                    }\r\n                }\r\n\r\n                while (true) {\r\n                    if (pseudoRegex(pattern, i, match, j))\r\n                        return true;\r\n                    j++;\r\n                    if (match.length == j)\r\n                        return false;\r\n                }\r\n            }\r\n\r\n            if (match.length == j)\r\n                return false;\r\n\r\n            if ((pattern[i] != '?') && (pattern[i] != match[j]))\r\n                return false;\r\n\r\n            i++;\r\n            j++;\r\n        }\r\n    }\r\n\r\n    private String[] recommendHostkeyAlgorithms(String hostname) {\r\n        String preferredAlgo = null;\r\n\r\n        Vector keys = getAllKeys(hostname);\r\n\r\n        for (int i = 0; i < keys.size(); i++) {\r\n            String thisAlgo = null;\r\n\r\n            if (keys.elementAt(i) instanceof RSAPublicKey)\r\n                thisAlgo = \"ssh-rsa\";\r\n            else if (keys.elementAt(i) instanceof DSAPublicKey)\r\n                thisAlgo = \"ssh-dss\";\r\n            else\r\n                continue;\r\n\r\n            if (preferredAlgo != null) {\r\n\t\t\t\t/* If we find different key types, then return null */\r\n\r\n                if (preferredAlgo.compareTo(thisAlgo) != 0)\r\n                    return null;\r\n\r\n\t\t\t\t/* OK, we found the same algo again, optimize */\r\n\r\n                continue;\r\n            }\r\n        }\r\n\r\n\t\t/* If we did not find anything that we know of, return null */\r\n\r\n        if (preferredAlgo == null)\r\n            return null;\r\n\r\n\t\t/* Now put the preferred algo to the start of the array.\r\n\t\t * You may ask yourself why we do it that way - basically, we could just\r\n\t\t * return only the preferred algorithm: since we have a saved key of that\r\n\t\t * type (sent earlier from the remote host), then that should work out.\r\n\t\t * However, imagine that the server is (for whatever reasons) not offering\r\n\t\t * that type of hostkey anymore (e.g., \"ssh-rsa\" was disabled and\r\n\t\t * now \"ssh-dss\" is being used). If we then do not let the server send us\r\n\t\t * a fresh key of the new type, then we shoot ourself into the foot:\r\n\t\t * the connection cannot be established and hence the user cannot decide\r\n\t\t * if he/she wants to accept the new key.\r\n\t\t */\r\n\r\n        if (preferredAlgo.equals(\"ssh-rsa\"))\r\n            return new String[]{\"ssh-rsa\", \"ssh-dss\"};\r\n\r\n        return new String[]{\"ssh-dss\", \"ssh-rsa\"};\r\n    }\r\n\r\n    /**\r\n     * Checks the internal hostkey database for the given hostkey.\r\n     * If no matching key can be found, then the hostname is resolved to an IP address\r\n     * and the search is repeated using that IP address.\r\n     *\r\n     * @param hostname               the server's hostname, will be matched with all hostname patterns\r\n     * @param serverHostKeyAlgorithm type of hostkey, either <code>ssh-rsa</code> or <code>ssh-dss</code>\r\n     * @param serverHostKey          the key blob\r\n     * @return <ul>\r\n     * <li><code>HOSTKEY_IS_OK</code>: the given hostkey matches an entry for the given hostname</li>\r\n     * <li><code>HOSTKEY_IS_NEW</code>: no entries found for this hostname and this type of hostkey</li>\r\n     * <li><code>HOSTKEY_HAS_CHANGED</code>: hostname is known, but with another key of the same type\r\n     * (man-in-the-middle attack?)</li>\r\n     * </ul>\r\n     * @throws IOException if the supplied key blob cannot be parsed or does not match the given hostkey type.\r\n     */\r\n    public int verifyHostkey(String hostname, String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException {\r\n        Object remoteKey = null;\r\n\r\n        if (\"ssh-rsa\".equals(serverHostKeyAlgorithm)) {\r\n            remoteKey = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey);\r\n        } else if (\"ssh-dss\".equals(serverHostKeyAlgorithm)) {\r\n            remoteKey = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);\r\n        } else\r\n            throw new IllegalArgumentException(\"Unknown hostkey type \" + serverHostKeyAlgorithm);\r\n\r\n        int result = checkKey(hostname, remoteKey);\r\n\r\n        if (result == HOSTKEY_IS_OK)\r\n            return result;\r\n\r\n        InetAddress[] ipAdresses = null;\r\n\r\n        try {\r\n            ipAdresses = InetAddress.getAllByName(hostname);\r\n        } catch (UnknownHostException e) {\r\n            return result;\r\n        }\r\n\r\n        for (int i = 0; i < ipAdresses.length; i++) {\r\n            int newresult = checkKey(ipAdresses[i].getHostAddress(), remoteKey);\r\n\r\n            if (newresult == HOSTKEY_IS_OK)\r\n                return newresult;\r\n\r\n            if (newresult == HOSTKEY_HAS_CHANGED)\r\n                result = HOSTKEY_HAS_CHANGED;\r\n        }\r\n\r\n        return result;\r\n    }\r\n\r\n    private class KnownHostsEntry {\r\n        String[] patterns;\r\n        Object key;\r\n\r\n        KnownHostsEntry(String[] patterns, Object key) {\r\n            this.patterns = patterns;\r\n            this.key = key;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/LocalPortForwarder.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.channel.ChannelManager;\r\nimport ch.ethz.ssh2.channel.LocalAcceptThread;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * A <code>LocalPortForwarder</code> forwards TCP/IP connections to a local\r\n * port via the secure tunnel to another host (which may or may not be identical\r\n * to the remote SSH-2 server).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: LocalPortForwarder.java,v 1.5 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\npublic class LocalPortForwarder {\r\n    ChannelManager cm;\r\n\r\n    int local_port;\r\n\r\n    String host_to_connect;\r\n\r\n    int port_to_connect;\r\n\r\n    LocalAcceptThread lat;\r\n\r\n    LocalPortForwarder(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect)\r\n            throws IOException {\r\n        this.cm = cm;\r\n        this.local_port = local_port;\r\n        this.host_to_connect = host_to_connect;\r\n        this.port_to_connect = port_to_connect;\r\n\r\n        lat = new LocalAcceptThread(cm, local_port, host_to_connect, port_to_connect);\r\n        lat.setDaemon(true);\r\n        lat.start();\r\n    }\r\n\r\n    /**\r\n     * Stop TCP/IP forwarding of newly arriving connections.\r\n     *\r\n     * @throws IOException\r\n     */\r\n    public void close() throws IOException {\r\n        lat.stopWorking();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/LocalStreamForwarder.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.channel.Channel;\r\nimport ch.ethz.ssh2.channel.ChannelManager;\r\nimport ch.ethz.ssh2.channel.LocalAcceptThread;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\n\r\n/**\r\n * A <code>LocalStreamForwarder</code> forwards an Input- and Outputstream\r\n * pair via the secure tunnel to another host (which may or may not be identical\r\n * to the remote SSH-2 server).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: LocalStreamForwarder.java,v 1.6 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\npublic class LocalStreamForwarder {\r\n    ChannelManager cm;\r\n\r\n    String host_to_connect;\r\n    int port_to_connect;\r\n    LocalAcceptThread lat;\r\n\r\n    Channel cn;\r\n\r\n    LocalStreamForwarder(ChannelManager cm, String host_to_connect, int port_to_connect) throws IOException {\r\n        this.cm = cm;\r\n        this.host_to_connect = host_to_connect;\r\n        this.port_to_connect = port_to_connect;\r\n\r\n        cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, \"127.0.0.1\", 0);\r\n    }\r\n\r\n    /**\r\n     * @return An <code>InputStream</code> object.\r\n     * @throws IOException\r\n     */\r\n    public InputStream getInputStream() throws IOException {\r\n        return cn.getStdoutStream();\r\n    }\r\n\r\n    /**\r\n     * Get the OutputStream. Please be aware that the implementation MAY use an\r\n     * internal buffer. To make sure that the buffered data is sent over the\r\n     * tunnel, you have to call the <code>flush</code> method of the\r\n     * <code>OutputStream</code>. To signal EOF, please use the\r\n     * <code>close</code> method of the <code>OutputStream</code>.\r\n     *\r\n     * @return An <code>OutputStream</code> object.\r\n     * @throws IOException\r\n     */\r\n    public OutputStream getOutputStream() throws IOException {\r\n        return cn.getStdinStream();\r\n    }\r\n\r\n    /**\r\n     * Close the underlying SSH forwarding channel and free up resources.\r\n     * You can also use this method to force the shutdown of the underlying\r\n     * forwarding channel. Pending output (OutputStream not flushed) will NOT\r\n     * be sent. Pending input (InputStream) can still be read. If the shutdown\r\n     * operation is already in progress (initiated from either side), then this\r\n     * call is a no-op.\r\n     *\r\n     * @throws IOException\r\n     */\r\n    public void close() throws IOException {\r\n        cm.closeChannel(cn, \"Closed due to user request.\", true);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/ProxyData.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * An abstract marker interface implemented by all proxy data implementations.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ProxyData.java,v 1.3 2006/08/02 12:17:22 cplattne Exp $\r\n * @see HTTPProxyData\r\n */\r\n\r\npublic abstract interface ProxyData {\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SCPClient.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport java.io.*;\r\n\r\n/**\r\n * A very basic <code>SCPClient</code> that can be used to copy files from/to\r\n * the SSH-2 server. On the server side, the \"scp\" program must be in the PATH.\r\n * <p>\r\n * This scp client is thread safe - you can download (and upload) different sets\r\n * of files concurrently without any troubles. The <code>SCPClient</code> is\r\n * actually mapping every request to a distinct {@link Session}.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SCPClient.java,v 1.11 2006/08/02 11:57:12 cplattne Exp $\r\n */\r\n\r\npublic class SCPClient {\r\n    Connection conn;\r\n\r\n    public SCPClient(Connection conn) {\r\n        if (conn == null)\r\n            throw new IllegalArgumentException(\"Cannot accept null argument!\");\r\n        this.conn = conn;\r\n    }\r\n\r\n    private void readResponse(InputStream is) throws IOException {\r\n        int c = is.read();\r\n\r\n        if (c == 0)\r\n            return;\r\n\r\n        if (c == -1)\r\n            throw new IOException(\"Remote scp terminated unexpectedly.\");\r\n\r\n        if ((c != 1) && (c != 2))\r\n            throw new IOException(\"Remote scp sent illegal error code.\");\r\n\r\n        if (c == 2)\r\n            throw new IOException(\"Remote scp terminated with error.\");\r\n\r\n        String err = receiveLine(is);\r\n        throw new IOException(\"Remote scp terminated with error (\" + err + \").\");\r\n    }\r\n\r\n    private String receiveLine(InputStream is) throws IOException {\r\n        StringBuffer sb = new StringBuffer(30);\r\n\r\n        while (true) {\r\n            /* This is a random limit - if your path names are longer, then adjust it */\r\n\r\n            if (sb.length() > 8192)\r\n                throw new IOException(\"Remote scp sent a too long line\");\r\n\r\n            int c = is.read();\r\n\r\n            if (c < 0)\r\n                throw new IOException(\"Remote scp terminated unexpectedly.\");\r\n\r\n            if (c == '\\n')\r\n                break;\r\n\r\n            sb.append((char) c);\r\n\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    private LenNamePair parseCLine(String line) throws IOException {\r\n\t\t/* Minimum line: \"xxxx y z\" ---> 8 chars */\r\n\r\n        long len;\r\n\r\n        if (line.length() < 8)\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary, line too short.\");\r\n\r\n        if ((line.charAt(4) != ' ') || (line.charAt(5) == ' '))\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary.\");\r\n\r\n        int length_name_sep = line.indexOf(' ', 5);\r\n\r\n        if (length_name_sep == -1)\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary.\");\r\n\r\n        String length_substring = line.substring(5, length_name_sep);\r\n        String name_substring = line.substring(length_name_sep + 1);\r\n\r\n        if ((length_substring.length() <= 0) || (name_substring.length() <= 0))\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary.\");\r\n\r\n        if ((6 + length_substring.length() + name_substring.length()) != line.length())\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary.\");\r\n\r\n        try {\r\n            len = Long.parseLong(length_substring);\r\n        } catch (NumberFormatException e) {\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary, cannot parse file length.\");\r\n        }\r\n\r\n        if (len < 0)\r\n            throw new IOException(\"Malformed C line sent by remote SCP binary, illegal file length.\");\r\n\r\n        LenNamePair lnp = new LenNamePair();\r\n        lnp.length = len;\r\n        lnp.filename = name_substring;\r\n\r\n        return lnp;\r\n    }\r\n\r\n    private void sendBytes(Session sess, byte[] data, String fileName, String mode) throws IOException {\r\n        OutputStream os = sess.getStdin();\r\n        InputStream is = new BufferedInputStream(sess.getStdout(), 512);\r\n\r\n        readResponse(is);\r\n\r\n        String cline = \"C\" + mode + \" \" + data.length + \" \" + fileName + \"\\n\";\r\n\r\n        os.write(cline.getBytes());\r\n        os.flush();\r\n\r\n        readResponse(is);\r\n\r\n        os.write(data, 0, data.length);\r\n        os.write(0);\r\n        os.flush();\r\n\r\n        readResponse(is);\r\n\r\n        os.write(\"E\\n\".getBytes());\r\n        os.flush();\r\n    }\r\n\r\n    private void sendFiles(Session sess, String[] files, String[] remoteFiles, String mode) throws IOException {\r\n        byte[] buffer = new byte[8192];\r\n\r\n        OutputStream os = new BufferedOutputStream(sess.getStdin(), 40000);\r\n        InputStream is = new BufferedInputStream(sess.getStdout(), 512);\r\n\r\n        readResponse(is);\r\n\r\n        for (int i = 0; i < files.length; i++) {\r\n            File f = new File(files[i]);\r\n            long remain = f.length();\r\n\r\n            String remoteName;\r\n\r\n            if ((remoteFiles != null) && (remoteFiles.length > i) && (remoteFiles[i] != null))\r\n                remoteName = remoteFiles[i];\r\n            else\r\n                remoteName = f.getName();\r\n\r\n            String cline = \"C\" + mode + \" \" + remain + \" \" + remoteName + \"\\n\";\r\n\r\n            os.write(cline.getBytes());\r\n            os.flush();\r\n\r\n            readResponse(is);\r\n\r\n            FileInputStream fis = null;\r\n\r\n            try {\r\n                fis = new FileInputStream(f);\r\n\r\n                while (remain > 0) {\r\n                    int trans;\r\n                    if (remain > buffer.length)\r\n                        trans = buffer.length;\r\n                    else\r\n                        trans = (int) remain;\r\n\r\n                    if (fis.read(buffer, 0, trans) != trans)\r\n                        throw new IOException(\"Cannot read enough from local file \" + files[i]);\r\n\r\n                    os.write(buffer, 0, trans);\r\n\r\n                    remain -= trans;\r\n                }\r\n            } finally {\r\n                if (fis != null)\r\n                    fis.close();\r\n            }\r\n\r\n            os.write(0);\r\n            os.flush();\r\n\r\n            readResponse(is);\r\n        }\r\n\r\n        os.write(\"E\\n\".getBytes());\r\n        os.flush();\r\n    }\r\n\r\n    private void receiveFiles(Session sess, OutputStream[] targets) throws IOException {\r\n        byte[] buffer = new byte[8192];\r\n\r\n        OutputStream os = new BufferedOutputStream(sess.getStdin(), 512);\r\n        InputStream is = new BufferedInputStream(sess.getStdout(), 40000);\r\n\r\n        os.write(0x0);\r\n        os.flush();\r\n\r\n        for (int i = 0; i < targets.length; i++) {\r\n            LenNamePair lnp = null;\r\n\r\n            while (true) {\r\n                int c = is.read();\r\n                if (c < 0)\r\n                    throw new IOException(\"Remote scp terminated unexpectedly.\");\r\n\r\n                String line = receiveLine(is);\r\n\r\n                if (c == 'T') {\r\n\t\t\t\t\t/* Ignore modification times */\r\n\r\n                    continue;\r\n                }\r\n\r\n                if ((c == 1) || (c == 2))\r\n                    throw new IOException(\"Remote SCP error: \" + line);\r\n\r\n                if (c == 'C') {\r\n                    lnp = parseCLine(line);\r\n                    break;\r\n\r\n                }\r\n                throw new IOException(\"Remote SCP error: \" + ((char) c) + line);\r\n            }\r\n\r\n            os.write(0x0);\r\n            os.flush();\r\n\r\n            long remain = lnp.length;\r\n\r\n            while (remain > 0) {\r\n                int trans;\r\n                if (remain > buffer.length)\r\n                    trans = buffer.length;\r\n                else\r\n                    trans = (int) remain;\r\n\r\n                int this_time_received = is.read(buffer, 0, trans);\r\n\r\n                if (this_time_received < 0) {\r\n                    throw new IOException(\"Remote scp terminated connection unexpectedly\");\r\n                }\r\n\r\n                targets[i].write(buffer, 0, this_time_received);\r\n\r\n                remain -= this_time_received;\r\n            }\r\n\r\n            readResponse(is);\r\n\r\n            os.write(0x0);\r\n            os.flush();\r\n        }\r\n    }\r\n\r\n    private void receiveFiles(Session sess, String[] files, String target) throws IOException {\r\n        byte[] buffer = new byte[8192];\r\n\r\n        OutputStream os = new BufferedOutputStream(sess.getStdin(), 512);\r\n        InputStream is = new BufferedInputStream(sess.getStdout(), 40000);\r\n\r\n        os.write(0x0);\r\n        os.flush();\r\n\r\n        for (int i = 0; i < files.length; i++) {\r\n            LenNamePair lnp = null;\r\n\r\n            while (true) {\r\n                int c = is.read();\r\n                if (c < 0)\r\n                    throw new IOException(\"Remote scp terminated unexpectedly.\");\r\n\r\n                String line = receiveLine(is);\r\n\r\n                if (c == 'T') {\r\n\t\t\t\t\t/* Ignore modification times */\r\n\r\n                    continue;\r\n                }\r\n\r\n                if ((c == 1) || (c == 2))\r\n                    throw new IOException(\"Remote SCP error: \" + line);\r\n\r\n                if (c == 'C') {\r\n                    lnp = parseCLine(line);\r\n                    break;\r\n\r\n                }\r\n                throw new IOException(\"Remote SCP error: \" + ((char) c) + line);\r\n            }\r\n\r\n            os.write(0x0);\r\n            os.flush();\r\n\r\n            File f = new File(target + File.separatorChar + lnp.filename);\r\n            FileOutputStream fop = null;\r\n\r\n            try {\r\n                fop = new FileOutputStream(f);\r\n\r\n                long remain = lnp.length;\r\n\r\n                while (remain > 0) {\r\n                    int trans;\r\n                    if (remain > buffer.length)\r\n                        trans = buffer.length;\r\n                    else\r\n                        trans = (int) remain;\r\n\r\n                    int this_time_received = is.read(buffer, 0, trans);\r\n\r\n                    if (this_time_received < 0) {\r\n                        throw new IOException(\"Remote scp terminated connection unexpectedly\");\r\n                    }\r\n\r\n                    fop.write(buffer, 0, this_time_received);\r\n\r\n                    remain -= this_time_received;\r\n                }\r\n            } finally {\r\n                if (fop != null)\r\n                    fop.close();\r\n            }\r\n\r\n            readResponse(is);\r\n\r\n            os.write(0x0);\r\n            os.flush();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Copy a local file to a remote directory, uses mode 0600 when creating\r\n     * the file on the remote side.\r\n     *\r\n     * @param localFile             Path and name of local file.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @throws IOException\r\n     */\r\n    public void put(String localFile, String remoteTargetDirectory) throws IOException {\r\n        put(new String[]{localFile}, remoteTargetDirectory, \"0600\");\r\n    }\r\n\r\n    /**\r\n     * Copy a set of local files to a remote directory, uses mode 0600 when\r\n     * creating files on the remote side.\r\n     *\r\n     * @param localFiles            Paths and names of local file names.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @throws IOException\r\n     */\r\n\r\n    public void put(String[] localFiles, String remoteTargetDirectory) throws IOException {\r\n        put(localFiles, remoteTargetDirectory, \"0600\");\r\n    }\r\n\r\n    /**\r\n     * Copy a local file to a remote directory, uses the specified mode when\r\n     * creating the file on the remote side.\r\n     *\r\n     * @param localFile             Path and name of local file.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @param mode                  a four digit string (e.g., 0644, see \"man chmod\", \"man open\")\r\n     * @throws IOException\r\n     */\r\n    public void put(String localFile, String remoteTargetDirectory, String mode) throws IOException {\r\n        put(new String[]{localFile}, remoteTargetDirectory, mode);\r\n    }\r\n\r\n    /**\r\n     * Copy a local file to a remote directory, uses the specified mode and remote filename\r\n     * when creating the file on the remote side.\r\n     *\r\n     * @param localFile             Path and name of local file.\r\n     * @param remoteFileName        The name of the file which will be created in the remote target directory.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @param mode                  a four digit string (e.g., 0644, see \"man chmod\", \"man open\")\r\n     * @throws IOException\r\n     */\r\n    public void put(String localFile, String remoteFileName, String remoteTargetDirectory, String mode)\r\n            throws IOException {\r\n        put(new String[]{localFile}, new String[]{remoteFileName}, remoteTargetDirectory, mode);\r\n    }\r\n\r\n    /**\r\n     * Create a remote file and copy the contents of the passed byte array into it.\r\n     * Uses mode 0600 for creating the remote file.\r\n     *\r\n     * @param data                  the data to be copied into the remote file.\r\n     * @param remoteFileName        The name of the file which will be created in the remote target directory.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @throws IOException\r\n     */\r\n\r\n    public void put(byte[] data, String remoteFileName, String remoteTargetDirectory) throws IOException {\r\n        put(data, remoteFileName, remoteTargetDirectory, \"0600\");\r\n    }\r\n\r\n    /**\r\n     * Create a remote file and copy the contents of the passed byte array into it.\r\n     * The method use the specified mode when creating the file on the remote side.\r\n     *\r\n     * @param data                  the data to be copied into the remote file.\r\n     * @param remoteFileName        The name of the file which will be created in the remote target directory.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @param mode                  a four digit string (e.g., 0644, see \"man chmod\", \"man open\")\r\n     * @throws IOException\r\n     */\r\n    public void put(byte[] data, String remoteFileName, String remoteTargetDirectory, String mode) throws IOException {\r\n        Session sess = null;\r\n\r\n        if ((remoteFileName == null) || (remoteTargetDirectory == null) || (mode == null))\r\n            throw new IllegalArgumentException(\"Null argument.\");\r\n\r\n        if (mode.length() != 4)\r\n            throw new IllegalArgumentException(\"Invalid mode.\");\r\n\r\n        for (int i = 0; i < mode.length(); i++)\r\n            if (Character.isDigit(mode.charAt(i)) == false)\r\n                throw new IllegalArgumentException(\"Invalid mode.\");\r\n\r\n        remoteTargetDirectory = remoteTargetDirectory.trim();\r\n        remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : \".\";\r\n\r\n        String cmd = \"scp -t -d \" + remoteTargetDirectory;\r\n\r\n        try {\r\n            sess = conn.openSession();\r\n            sess.execCommand(cmd);\r\n            sendBytes(sess, data, remoteFileName, mode);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"Error during SCP transfer.\").initCause(e);\r\n        } finally {\r\n            if (sess != null)\r\n                sess.close();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Copy a set of local files to a remote directory, uses the specified mode\r\n     * when creating the files on the remote side.\r\n     *\r\n     * @param localFiles            Paths and names of the local files.\r\n     * @param remoteTargetDirectory Remote target directory. Use an empty string to specify the default directory.\r\n     * @param mode                  a four digit string (e.g., 0644, see \"man chmod\", \"man open\")\r\n     * @throws IOException\r\n     */\r\n    public void put(String[] localFiles, String remoteTargetDirectory, String mode) throws IOException {\r\n        put(localFiles, null, remoteTargetDirectory, mode);\r\n    }\r\n\r\n    public void put(String[] localFiles, String[] remoteFiles, String remoteTargetDirectory, String mode)\r\n            throws IOException {\r\n        Session sess = null;\r\n\r\n\t\t/* remoteFiles may be null, indicating that the local filenames shall be used */\r\n\r\n        if ((localFiles == null) || (remoteTargetDirectory == null) || (mode == null))\r\n            throw new IllegalArgumentException(\"Null argument.\");\r\n\r\n        if (mode.length() != 4)\r\n            throw new IllegalArgumentException(\"Invalid mode.\");\r\n\r\n        for (int i = 0; i < mode.length(); i++)\r\n            if (Character.isDigit(mode.charAt(i)) == false)\r\n                throw new IllegalArgumentException(\"Invalid mode.\");\r\n\r\n        if (localFiles.length == 0)\r\n            return;\r\n\r\n        remoteTargetDirectory = remoteTargetDirectory.trim();\r\n        remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : \".\";\r\n\r\n        String cmd = \"scp -t -d \" + remoteTargetDirectory;\r\n\r\n        for (int i = 0; i < localFiles.length; i++) {\r\n            if (localFiles[i] == null)\r\n                throw new IllegalArgumentException(\"Cannot accept null filename.\");\r\n        }\r\n\r\n        try {\r\n            sess = conn.openSession();\r\n            sess.execCommand(cmd);\r\n            sendFiles(sess, localFiles, remoteFiles, mode);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"Error during SCP transfer.\").initCause(e);\r\n        } finally {\r\n            if (sess != null)\r\n                sess.close();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Download a file from the remote server to a local directory.\r\n     *\r\n     * @param remoteFile           Path and name of the remote file.\r\n     * @param localTargetDirectory Local directory to put the downloaded file.\r\n     * @throws IOException\r\n     */\r\n    public void get(String remoteFile, String localTargetDirectory) throws IOException {\r\n        get(new String[]{remoteFile}, localTargetDirectory);\r\n    }\r\n\r\n    /**\r\n     * Download a file from the remote server and pipe its contents into an <code>OutputStream</code>.\r\n     * Please note that, to enable flexible usage of this method, the <code>OutputStream</code> will not\r\n     * be closed nor flushed.\r\n     *\r\n     * @param remoteFile Path and name of the remote file.\r\n     * @param target     OutputStream where the contents of the file will be sent to.\r\n     * @throws IOException\r\n     */\r\n    public void get(String remoteFile, OutputStream target) throws IOException {\r\n        get(new String[]{remoteFile}, new OutputStream[]{target});\r\n    }\r\n\r\n    private void get(String remoteFiles[], OutputStream[] targets) throws IOException {\r\n        Session sess = null;\r\n\r\n        if ((remoteFiles == null) || (targets == null))\r\n            throw new IllegalArgumentException(\"Null argument.\");\r\n\r\n        if (remoteFiles.length != targets.length)\r\n            throw new IllegalArgumentException(\"Length of arguments does not match.\");\r\n\r\n        if (remoteFiles.length == 0)\r\n            return;\r\n\r\n        String cmd = \"scp -f\";\r\n\r\n        for (int i = 0; i < remoteFiles.length; i++) {\r\n            if (remoteFiles[i] == null)\r\n                throw new IllegalArgumentException(\"Cannot accept null filename.\");\r\n\r\n            String tmp = remoteFiles[i].trim();\r\n\r\n            if (tmp.length() == 0)\r\n                throw new IllegalArgumentException(\"Cannot accept empty filename.\");\r\n\r\n            cmd += (\" \" + tmp);\r\n        }\r\n\r\n        try {\r\n            sess = conn.openSession();\r\n            sess.execCommand(cmd);\r\n            receiveFiles(sess, targets);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"Error during SCP transfer.\").initCause(e);\r\n        } finally {\r\n            if (sess != null)\r\n                sess.close();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Download a set of files from the remote server to a local directory.\r\n     *\r\n     * @param remoteFiles          Paths and names of the remote files.\r\n     * @param localTargetDirectory Local directory to put the downloaded files.\r\n     * @throws IOException\r\n     */\r\n    public void get(String remoteFiles[], String localTargetDirectory) throws IOException {\r\n        Session sess = null;\r\n\r\n        if ((remoteFiles == null) || (localTargetDirectory == null))\r\n            throw new IllegalArgumentException(\"Null argument.\");\r\n\r\n        if (remoteFiles.length == 0)\r\n            return;\r\n\r\n        String cmd = \"scp -f\";\r\n\r\n        for (int i = 0; i < remoteFiles.length; i++) {\r\n            if (remoteFiles[i] == null)\r\n                throw new IllegalArgumentException(\"Cannot accept null filename.\");\r\n\r\n            String tmp = remoteFiles[i].trim();\r\n\r\n            if (tmp.length() == 0)\r\n                throw new IllegalArgumentException(\"Cannot accept empty filename.\");\r\n\r\n            cmd += (\" \" + tmp);\r\n        }\r\n\r\n        try {\r\n            sess = conn.openSession();\r\n            sess.execCommand(cmd);\r\n            receiveFiles(sess, remoteFiles, localTargetDirectory);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"Error during SCP transfer.\").initCause(e);\r\n        } finally {\r\n            if (sess != null)\r\n                sess.close();\r\n        }\r\n    }\r\n\r\n    class LenNamePair {\r\n        long length;\r\n        String filename;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SFTPException.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.sftp.ErrorCodes;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * Used in combination with the SFTPv3Client. This exception wraps\r\n * error messages sent by the SFTP server.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SFTPException.java,v 1.6 2006/08/18 22:26:35 cplattne Exp $\r\n */\r\n\r\npublic class SFTPException extends IOException {\r\n    private static final long serialVersionUID = 578654644222421811L;\r\n\r\n    private final String sftpErrorMessage;\r\n    private final int sftpErrorCode;\r\n\r\n    SFTPException(String msg, int errorCode) {\r\n        super(constructMessage(msg, errorCode));\r\n        sftpErrorMessage = msg;\r\n        sftpErrorCode = errorCode;\r\n    }\r\n\r\n    private static String constructMessage(String s, int errorCode) {\r\n        String[] detail = ErrorCodes.getDescription(errorCode);\r\n\r\n        if (detail == null)\r\n            return s + \" (UNKNOW SFTP ERROR CODE)\";\r\n\r\n        return s + \" (\" + detail[0] + \": \" + detail[1] + \")\";\r\n    }\r\n\r\n    /**\r\n     * Get the error message sent by the server. Often, this\r\n     * message does not help a lot (e.g., \"failure\").\r\n     *\r\n     * @return the plain string as sent by the server.\r\n     */\r\n    public String getServerErrorMessage() {\r\n        return sftpErrorMessage;\r\n    }\r\n\r\n    /**\r\n     * Get the error code sent by the server.\r\n     *\r\n     * @return an error code as defined in the SFTP specs.\r\n     */\r\n    public int getServerErrorCode() {\r\n        return sftpErrorCode;\r\n    }\r\n\r\n    /**\r\n     * Get the symbolic name of the error code as given in the SFTP specs.\r\n     *\r\n     * @return e.g., \"SSH_FX_INVALID_FILENAME\".\r\n     */\r\n    public String getServerErrorCodeSymbol() {\r\n        String[] detail = ErrorCodes.getDescription(sftpErrorCode);\r\n\r\n        if (detail == null)\r\n            return \"UNKNOW SFTP ERROR CODE \" + sftpErrorCode;\r\n\r\n        return detail[0];\r\n    }\r\n\r\n    /**\r\n     * Get the description of the error code as given in the SFTP specs.\r\n     *\r\n     * @return e.g., \"The filename is not valid.\"\r\n     */\r\n    public String getServerErrorCodeVerbose() {\r\n        String[] detail = ErrorCodes.getDescription(sftpErrorCode);\r\n\r\n        if (detail == null)\r\n            return \"The error code \" + sftpErrorCode + \" is unknown.\";\r\n\r\n        return detail[1];\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SFTPv3Client.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.packets.TypesReader;\r\nimport ch.ethz.ssh2.packets.TypesWriter;\r\nimport ch.ethz.ssh2.sftp.AttribFlags;\r\nimport ch.ethz.ssh2.sftp.ErrorCodes;\r\nimport ch.ethz.ssh2.sftp.Packet;\r\n\r\nimport java.io.*;\r\nimport java.nio.charset.Charset;\r\nimport java.util.HashMap;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * A <code>SFTPv3Client</code> represents a SFTP (protocol version 3)\r\n * client connection tunnelled over a SSH-2 connection. This is a very simple\r\n * (synchronous) implementation.\r\n * <p>\r\n * Basically, most methods in this class map directly to one of\r\n * the packet types described in draft-ietf-secsh-filexfer-02.txt.\r\n * <p>\r\n * Note: this is experimental code.\r\n * <p>\r\n * Error handling: the methods of this class throw IOExceptions. However, unless\r\n * there is catastrophic failure, exceptions of the type {@link SFTPv3Client} will\r\n * be thrown (a subclass of IOException). Therefore, you can implement more verbose\r\n * behavior by checking if a thrown exception if of this type. If yes, then you\r\n * can cast the exception and access detailed information about the failure.\r\n * <p>\r\n * Notes about file names, directory names and paths, copy-pasted\r\n * from the specs:\r\n * <ul>\r\n * <li>SFTP v3 represents file names as strings. File names are\r\n * assumed to use the slash ('/') character as a directory separator.</li>\r\n * <li>File names starting with a slash are \"absolute\", and are relative to\r\n * the root of the file system.  Names starting with any other character\r\n * are relative to the user's default directory (home directory).</li>\r\n * <li>Servers SHOULD interpret a path name component \"..\" as referring to\r\n * the parent directory, and \".\" as referring to the current directory.\r\n * If the server implementation limits access to certain parts of the\r\n * file system, it must be extra careful in parsing file names when\r\n * enforcing such restrictions.  There have been numerous reported\r\n * security bugs where a \"..\" in a path name has allowed access outside\r\n * the intended area.</li>\r\n * <li>An empty path name is valid, and it refers to the user's default\r\n * directory (usually the user's home directory).</li>\r\n * </ul>\r\n * <p>\r\n * If you are still not tired then please go on and read the comment for\r\n * {@link #setCharset(String)}.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SFTPv3Client.java,v 1.9 2006/09/20 12:51:37 cplattne Exp $\r\n */\r\npublic class SFTPv3Client {\r\n    final Connection conn;\r\n    final Session sess;\r\n    final PrintStream debug;\r\n\r\n    boolean flag_closed = false;\r\n\r\n    InputStream is;\r\n    OutputStream os;\r\n\r\n    int protocol_version = 0;\r\n    HashMap server_extensions = new HashMap();\r\n\r\n    int next_request_id = 1000;\r\n\r\n    String charsetName = null;\r\n\r\n    /**\r\n     * Create a SFTP v3 client.\r\n     *\r\n     * @param conn  The underlying SSH-2 connection to be used.\r\n     * @param debug\r\n     * @throws IOException\r\n     * @deprecated this constructor (debug version) will disappear in the future,\r\n     * use {@link #SFTPv3Client(Connection)} instead.\r\n     */\r\n    public SFTPv3Client(Connection conn, PrintStream debug) throws IOException {\r\n        if (conn == null)\r\n            throw new IllegalArgumentException(\"Cannot accept null argument!\");\r\n\r\n        this.conn = conn;\r\n        this.debug = debug;\r\n\r\n        if (debug != null)\r\n            debug.println(\"Opening session and starting SFTP subsystem.\");\r\n\r\n        sess = conn.openSession();\r\n        sess.startSubSystem(\"sftp\");\r\n\r\n        is = sess.getStdout();\r\n        os = new BufferedOutputStream(sess.getStdin(), 2048);\r\n\r\n        if ((is == null) || (os == null))\r\n            throw new IOException(\"There is a problem with the streams of the underlying channel.\");\r\n\r\n        init();\r\n    }\r\n\r\n    /**\r\n     * Create a SFTP v3 client.\r\n     *\r\n     * @param conn The underlying SSH-2 connection to be used.\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3Client(Connection conn) throws IOException {\r\n        this(conn, null);\r\n    }\r\n\r\n    /**\r\n     * The currently used charset for filename encoding/decoding.\r\n     *\r\n     * @return The name of the charset (<code>null</code> if the platform's default charset is being used)\r\n     * @see #setCharset(String)\r\n     */\r\n    public String getCharset() {\r\n        return charsetName;\r\n    }\r\n\r\n    /**\r\n     * Set the charset used to convert between Java Unicode Strings and byte encodings\r\n     * used by the server for paths and file names. Unfortunately, the SFTP v3 draft\r\n     * says NOTHING about such conversions (well, with the exception of error messages\r\n     * which have to be in UTF-8). Newer drafts specify to use UTF-8 for file names\r\n     * (if I remember correctly). However, a quick test using OpenSSH serving a EXT-3\r\n     * filesystem has shown that UTF-8 seems to be a bad choice for SFTP v3 (tested with\r\n     * filenames containing german umlauts). \"windows-1252\" seems to work better for Europe.\r\n     * Luckily, \"windows-1252\" is the platform default in my case =).\r\n     * <p>\r\n     * If you don't set anything, then the platform default will be used (this is the default\r\n     * behavior).\r\n     *\r\n     * @param charset the name of the charset to be used or <code>null</code> to use the platform's\r\n     *                default encoding.\r\n     * @throws IOException\r\n     * @see #getCharset()\r\n     */\r\n    public void setCharset(String charset) throws IOException {\r\n        if (charset == null) {\r\n            charsetName = charset;\r\n            return;\r\n        }\r\n\r\n        try {\r\n            Charset.forName(charset);\r\n        } catch (Exception e) {\r\n            throw (IOException) new IOException(\"This charset is not supported\").initCause(e);\r\n        }\r\n        charsetName = charset;\r\n    }\r\n\r\n    private final void checkHandleValidAndOpen(SFTPv3FileHandle handle) throws IOException {\r\n        if (handle.client != this)\r\n            throw new IOException(\"The file handle was created with another SFTPv3FileHandle instance.\");\r\n\r\n        if (handle.isClosed == true)\r\n            throw new IOException(\"The file handle is closed.\");\r\n    }\r\n\r\n    private final void sendMessage(int type, int requestId, byte[] msg, int off, int len) throws IOException {\r\n        int msglen = len + 1;\r\n\r\n        if (type != Packet.SSH_FXP_INIT)\r\n            msglen += 4;\r\n\r\n        os.write(msglen >> 24);\r\n        os.write(msglen >> 16);\r\n        os.write(msglen >> 8);\r\n        os.write(msglen);\r\n        os.write(type);\r\n\r\n        if (type != Packet.SSH_FXP_INIT) {\r\n            os.write(requestId >> 24);\r\n            os.write(requestId >> 16);\r\n            os.write(requestId >> 8);\r\n            os.write(requestId);\r\n        }\r\n\r\n        os.write(msg, off, len);\r\n        os.flush();\r\n    }\r\n\r\n    private final void sendMessage(int type, int requestId, byte[] msg) throws IOException {\r\n        sendMessage(type, requestId, msg, 0, msg.length);\r\n    }\r\n\r\n    private final void readBytes(byte[] buff, int pos, int len) throws IOException {\r\n        while (len > 0) {\r\n            int count = is.read(buff, pos, len);\r\n            if (count < 0)\r\n                throw new IOException(\"Unexpected end of sftp stream.\");\r\n            if ((count == 0) || (count > len))\r\n                throw new IOException(\"Underlying stream implementation is bogus!\");\r\n            len -= count;\r\n            pos += count;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Read a message and guarantee that the <b>contents</b> is not larger than\r\n     * <code>maxlen</code> bytes.\r\n     * <p>\r\n     * Note: receiveMessage(34000) actually means that the message may be up to 34004\r\n     * bytes (the length attribute preceeding the contents is 4 bytes).\r\n     *\r\n     * @param maxlen\r\n     * @return the message contents\r\n     * @throws IOException\r\n     */\r\n    private final byte[] receiveMessage(int maxlen) throws IOException {\r\n        byte[] msglen = new byte[4];\r\n\r\n        readBytes(msglen, 0, 4);\r\n\r\n        int len = (((msglen[0] & 0xff) << 24) | ((msglen[1] & 0xff) << 16) | ((msglen[2] & 0xff) << 8) | (msglen[3] & 0xff));\r\n\r\n        if ((len > maxlen) || (len <= 0))\r\n            throw new IOException(\"Illegal sftp packet len: \" + len);\r\n\r\n        byte[] msg = new byte[len];\r\n\r\n        readBytes(msg, 0, len);\r\n\r\n        return msg;\r\n    }\r\n\r\n    private final int generateNextRequestID() {\r\n        synchronized (this) {\r\n            return next_request_id++;\r\n        }\r\n    }\r\n\r\n    private final void closeHandle(byte[] handle) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(handle, 0, handle.length);\r\n\r\n        sendMessage(Packet.SSH_FXP_CLOSE, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    private SFTPv3FileAttributes readAttrs(TypesReader tr) throws IOException {\r\n        /*\r\n\t\t * uint32   flags\r\n\t\t * uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE\r\n\t\t * uint32   uid            present only if flag SSH_FILEXFER_ATTR_V3_UIDGID\r\n\t\t * uint32   gid            present only if flag SSH_FILEXFER_ATTR_V3_UIDGID\r\n\t\t * uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS\r\n\t\t * uint32   atime          present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME\r\n\t\t * uint32   mtime          present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME\r\n\t\t * uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED\r\n\t\t * string   extended_type\r\n\t\t * string   extended_data\r\n\t\t * ...      more extended data (extended_type - extended_data pairs),\r\n\t\t *          so that number of pairs equals extended_count\r\n\t\t */\r\n\r\n        SFTPv3FileAttributes fa = new SFTPv3FileAttributes();\r\n\r\n        int flags = tr.readUINT32();\r\n\r\n        if ((flags & AttribFlags.SSH_FILEXFER_ATTR_SIZE) != 0) {\r\n            if (debug != null)\r\n                debug.println(\"SSH_FILEXFER_ATTR_SIZE\");\r\n            fa.size = new Long(tr.readUINT64());\r\n        }\r\n\r\n        if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID) != 0) {\r\n            if (debug != null)\r\n                debug.println(\"SSH_FILEXFER_ATTR_V3_UIDGID\");\r\n            fa.uid = new Integer(tr.readUINT32());\r\n            fa.gid = new Integer(tr.readUINT32());\r\n        }\r\n\r\n        if ((flags & AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {\r\n            if (debug != null)\r\n                debug.println(\"SSH_FILEXFER_ATTR_PERMISSIONS\");\r\n            fa.permissions = new Integer(tr.readUINT32());\r\n        }\r\n\r\n        if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME) != 0) {\r\n            if (debug != null)\r\n                debug.println(\"SSH_FILEXFER_ATTR_V3_ACMODTIME\");\r\n            fa.atime = new Integer(tr.readUINT32());\r\n            fa.mtime = new Integer(tr.readUINT32());\r\n\r\n        }\r\n\r\n        if ((flags & AttribFlags.SSH_FILEXFER_ATTR_EXTENDED) != 0) {\r\n            int count = tr.readUINT32();\r\n\r\n            if (debug != null)\r\n                debug.println(\"SSH_FILEXFER_ATTR_EXTENDED (\" + count + \")\");\r\n\r\n\t\t\t/* Read it anyway to detect corrupt packets */\r\n\r\n            while (count > 0) {\r\n                tr.readByteString();\r\n                tr.readByteString();\r\n                count--;\r\n            }\r\n        }\r\n\r\n        return fa;\r\n    }\r\n\r\n    /**\r\n     * Retrieve the file attributes of an open file.\r\n     *\r\n     * @param handle a SFTPv3FileHandle handle.\r\n     * @return a SFTPv3FileAttributes object.\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileAttributes fstat(SFTPv3FileHandle handle) throws IOException {\r\n        checkHandleValidAndOpen(handle);\r\n\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_FSTAT...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_FSTAT, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Got REPLY.\");\r\n            debug.flush();\r\n        }\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_ATTRS) {\r\n            return readAttrs(tr);\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        throw new SFTPException(tr.readString(), errorCode);\r\n    }\r\n\r\n    private SFTPv3FileAttributes statBoth(String path, int statMethod) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(path, charsetName);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_STAT/SSH_FXP_LSTAT...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(statMethod, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Got REPLY.\");\r\n            debug.flush();\r\n        }\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_ATTRS) {\r\n            return readAttrs(tr);\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        throw new SFTPException(tr.readString(), errorCode);\r\n    }\r\n\r\n    /**\r\n     * Retrieve the file attributes of a file. This method\r\n     * follows symbolic links on the server.\r\n     *\r\n     * @param path See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileAttributes object.\r\n     * @throws IOException\r\n     * @see #lstat(String)\r\n     */\r\n    public SFTPv3FileAttributes stat(String path) throws IOException {\r\n        return statBoth(path, Packet.SSH_FXP_STAT);\r\n    }\r\n\r\n    /**\r\n     * Retrieve the file attributes of a file. This method\r\n     * does NOT follow symbolic links on the server.\r\n     *\r\n     * @param path See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileAttributes object.\r\n     * @throws IOException\r\n     * @see #stat(String)\r\n     */\r\n    public SFTPv3FileAttributes lstat(String path) throws IOException {\r\n        return statBoth(path, Packet.SSH_FXP_LSTAT);\r\n    }\r\n\r\n    /**\r\n     * Read the target of a symbolic link.\r\n     *\r\n     * @param path See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return The target of the link.\r\n     * @throws IOException\r\n     */\r\n    public String readLink(String path) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(path, charsetName);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_READLINK...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_READLINK, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Got REPLY.\");\r\n            debug.flush();\r\n        }\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_NAME) {\r\n            int count = tr.readUINT32();\r\n\r\n            if (count != 1)\r\n                throw new IOException(\"The server sent an invalid SSH_FXP_NAME packet.\");\r\n\r\n            return tr.readString(charsetName);\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        throw new SFTPException(tr.readString(), errorCode);\r\n    }\r\n\r\n    private void expectStatusOKMessage(int id) throws IOException {\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Got REPLY.\");\r\n            debug.flush();\r\n        }\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        if (errorCode == ErrorCodes.SSH_FX_OK)\r\n            return;\r\n\r\n        throw new SFTPException(tr.readString(), errorCode);\r\n    }\r\n\r\n    /**\r\n     * Modify the attributes of a file. Used for operations such as changing\r\n     * the ownership, permissions or access times, as well as for truncating a file.\r\n     *\r\n     * @param path See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param attr A SFTPv3FileAttributes object. Specifies the modifications to be\r\n     *             made to the attributes of the file. Empty fields will be ignored.\r\n     * @throws IOException\r\n     */\r\n    public void setstat(String path, SFTPv3FileAttributes attr) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(path, charsetName);\r\n        tw.writeBytes(createAttrs(attr));\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_SETSTAT...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_SETSTAT, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Modify the attributes of a file. Used for operations such as changing\r\n     * the ownership, permissions or access times, as well as for truncating a file.\r\n     *\r\n     * @param handle a SFTPv3FileHandle handle\r\n     * @param attr   A SFTPv3FileAttributes object. Specifies the modifications to be\r\n     *               made to the attributes of the file. Empty fields will be ignored.\r\n     * @throws IOException\r\n     */\r\n    public void fsetstat(SFTPv3FileHandle handle, SFTPv3FileAttributes attr) throws IOException {\r\n        checkHandleValidAndOpen(handle);\r\n\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);\r\n        tw.writeBytes(createAttrs(attr));\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_FSETSTAT...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_FSETSTAT, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Create a symbolic link on the server. Creates a link \"src\" that points\r\n     * to \"target\".\r\n     *\r\n     * @param src    See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param target See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @throws IOException\r\n     */\r\n    public void createSymlink(String src, String target) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n\t\t/* Either I am too stupid to understand the SFTP draft\r\n\t\t * or the OpenSSH guys changed the semantics of src and target.\r\n\t\t */\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(target, charsetName);\r\n        tw.writeString(src, charsetName);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_SYMLINK...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_SYMLINK, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Have the server canonicalize any given path name to an absolute path.\r\n     * This is useful for converting path names containing \"..\" components or\r\n     * relative pathnames without a leading slash into absolute paths.\r\n     *\r\n     * @param path See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return An absolute path.\r\n     * @throws IOException\r\n     */\r\n    public String canonicalPath(String path) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(path, charsetName);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_REALPATH...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_REALPATH, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Got REPLY.\");\r\n            debug.flush();\r\n        }\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_NAME) {\r\n            int count = tr.readUINT32();\r\n\r\n            if (count != 1)\r\n                throw new IOException(\"The server sent an invalid SSH_FXP_NAME packet.\");\r\n\r\n            return tr.readString(charsetName);\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        throw new SFTPException(tr.readString(), errorCode);\r\n    }\r\n\r\n    private final Vector scanDirectory(byte[] handle) throws IOException {\r\n        Vector files = new Vector();\r\n\r\n        while (true) {\r\n            int req_id = generateNextRequestID();\r\n\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeString(handle, 0, handle.length);\r\n\r\n            if (debug != null) {\r\n                debug.println(\"Sending SSH_FXP_READDIR...\");\r\n                debug.flush();\r\n            }\r\n\r\n            sendMessage(Packet.SSH_FXP_READDIR, req_id, tw.getBytes());\r\n\r\n            byte[] resp = receiveMessage(34000);\r\n\r\n            if (debug != null) {\r\n                debug.println(\"Got REPLY.\");\r\n                debug.flush();\r\n            }\r\n\r\n            TypesReader tr = new TypesReader(resp);\r\n\r\n            int t = tr.readByte();\r\n\r\n            int rep_id = tr.readUINT32();\r\n            if (rep_id != req_id)\r\n                throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n            if (t == Packet.SSH_FXP_NAME) {\r\n                int count = tr.readUINT32();\r\n\r\n                if (debug != null)\r\n                    debug.println(\"Parsing \" + count + \" name entries...\");\r\n\r\n                while (count > 0) {\r\n                    SFTPv3DirectoryEntry dirEnt = new SFTPv3DirectoryEntry();\r\n\r\n                    dirEnt.filename = tr.readString(charsetName);\r\n                    dirEnt.longEntry = tr.readString(charsetName);\r\n\r\n                    dirEnt.attributes = readAttrs(tr);\r\n                    files.addElement(dirEnt);\r\n\r\n                    if (debug != null)\r\n                        debug.println(\"File: '\" + dirEnt.filename + \"'\");\r\n                    count--;\r\n                }\r\n                continue;\r\n            }\r\n\r\n            if (t != Packet.SSH_FXP_STATUS)\r\n                throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n            int errorCode = tr.readUINT32();\r\n\r\n            if (errorCode == ErrorCodes.SSH_FX_EOF)\r\n                return files;\r\n\r\n            throw new SFTPException(tr.readString(), errorCode);\r\n        }\r\n    }\r\n\r\n    private final byte[] openDirectory(String path) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(path, charsetName);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_OPENDIR...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_OPENDIR, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_HANDLE) {\r\n            if (debug != null) {\r\n                debug.println(\"Got SSH_FXP_HANDLE.\");\r\n                debug.flush();\r\n            }\r\n\r\n            byte[] handle = tr.readByteString();\r\n            return handle;\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n        String errorMessage = tr.readString();\r\n\r\n        throw new SFTPException(errorMessage, errorCode);\r\n    }\r\n\r\n    private final String expandString(byte[] b, int off, int len) {\r\n        StringBuffer sb = new StringBuffer();\r\n\r\n        for (int i = 0; i < len; i++) {\r\n            int c = b[off + i] & 0xff;\r\n\r\n            if ((c >= 32) && (c <= 126)) {\r\n                sb.append((char) c);\r\n            } else {\r\n                sb.append(\"{0x\" + Integer.toHexString(c) + \"}\");\r\n            }\r\n        }\r\n\r\n        return sb.toString();\r\n    }\r\n\r\n    private void init() throws IOException {\r\n\t\t/* Send SSH_FXP_INIT (version 3) */\r\n\r\n        final int client_version = 3;\r\n\r\n        if (debug != null)\r\n            debug.println(\"Sending SSH_FXP_INIT (\" + client_version + \")...\");\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeUINT32(client_version);\r\n        sendMessage(Packet.SSH_FXP_INIT, 0, tw.getBytes());\r\n\r\n\t\t/* Receive SSH_FXP_VERSION */\r\n\r\n        if (debug != null)\r\n            debug.println(\"Waiting for SSH_FXP_VERSION...\");\r\n\r\n        TypesReader tr = new TypesReader(receiveMessage(34000)); /* Should be enough for any reasonable server */\r\n\r\n        int type = tr.readByte();\r\n\r\n        if (type != Packet.SSH_FXP_VERSION) {\r\n            throw new IOException(\"The server did not send a SSH_FXP_VERSION packet (got \" + type + \")\");\r\n        }\r\n\r\n        protocol_version = tr.readUINT32();\r\n\r\n        if (debug != null)\r\n            debug.println(\"SSH_FXP_VERSION: protocol_version = \" + protocol_version);\r\n\r\n        if (protocol_version != 3)\r\n            throw new IOException(\"Server version \" + protocol_version + \" is currently not supported\");\r\n\r\n\t\t/* Read and save extensions (if any) for later use */\r\n\r\n        while (tr.remain() != 0) {\r\n            String name = tr.readString();\r\n            byte[] value = tr.readByteString();\r\n            server_extensions.put(name, value);\r\n\r\n            if (debug != null)\r\n                debug.println(\"SSH_FXP_VERSION: extension: \" + name + \" = '\" + expandString(value, 0, value.length)\r\n                        + \"'\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the negotiated SFTP protocol version between the client and the server.\r\n     *\r\n     * @return SFTP protocol version, i.e., \"3\".\r\n     */\r\n    public int getProtocolVersion() {\r\n        return protocol_version;\r\n    }\r\n\r\n    /**\r\n     * Close this SFTP session. NEVER forget to call this method to free up\r\n     * resources - even if you got an exception from one of the other methods.\r\n     * Sometimes these other methods may throw an exception, saying that the\r\n     * underlying channel is closed (this can happen, e.g., if the other server\r\n     * sent a close message.) However, as long as you have not called the\r\n     * <code>close()</code> method, you are likely wasting resources.\r\n     */\r\n    public void close() {\r\n        sess.close();\r\n    }\r\n\r\n    /**\r\n     * List the contents of a directory.\r\n     *\r\n     * @param dirName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return A Vector containing {@link SFTPv3DirectoryEntry} objects.\r\n     * @throws IOException\r\n     */\r\n    public Vector ls(String dirName) throws IOException {\r\n        byte[] handle = openDirectory(dirName);\r\n        Vector result = scanDirectory(handle);\r\n        closeHandle(handle);\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Create a new directory.\r\n     *\r\n     * @param dirName          See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param posixPermissions the permissions for this directory, e.g., \"0700\". The server\r\n     *                         will likely apply a umask.\r\n     * @throws IOException\r\n     */\r\n    public void mkdir(String dirName, int posixPermissions) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(dirName, charsetName);\r\n        tw.writeUINT32(AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS);\r\n        tw.writeUINT32(posixPermissions);\r\n\r\n        sendMessage(Packet.SSH_FXP_MKDIR, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Remove a file.\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @throws IOException\r\n     */\r\n    public void rm(String fileName) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(fileName, charsetName);\r\n\r\n        sendMessage(Packet.SSH_FXP_REMOVE, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Remove an empty directory.\r\n     *\r\n     * @param dirName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @throws IOException\r\n     */\r\n    public void rmdir(String dirName) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(dirName, charsetName);\r\n\r\n        sendMessage(Packet.SSH_FXP_RMDIR, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Move a file or directory.\r\n     *\r\n     * @param oldPath See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param newPath See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @throws IOException\r\n     */\r\n    public void mv(String oldPath, String newPath) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(oldPath, charsetName);\r\n        tw.writeString(newPath, charsetName);\r\n\r\n        sendMessage(Packet.SSH_FXP_RENAME, req_id, tw.getBytes());\r\n\r\n        expectStatusOKMessage(req_id);\r\n    }\r\n\r\n    /**\r\n     * Open a file for reading.\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle openFileRO(String fileName) throws IOException {\r\n        return openFile(fileName, 0x00000001, null); // SSH_FXF_READ\r\n    }\r\n\r\n    /**\r\n     * Open a file for reading and writing.\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle openFileRW(String fileName) throws IOException {\r\n        return openFile(fileName, 0x00000003, null); // SSH_FXF_READ | SSH_FXF_WRITE\r\n    }\r\n\r\n    // Append is broken (already in the specification, because there is no way to\r\n    // send a write operation (what offset to use??))\r\n    //\tpublic SFTPv3FileHandle openFileRWAppend(String fileName) throws IOException\r\n    //\t{\r\n    //\t\treturn openFile(fileName, 0x00000007, null); // SSH_FXF_READ | SSH_FXF_WRITE | SSH_FXF_APPEND\r\n    //\t}\r\n\r\n    /**\r\n     * Create a file and open it for reading and writing.\r\n     * Same as {@link #createFile(String, SFTPv3FileAttributes) createFile(fileName, null)}.\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle createFile(String fileName) throws IOException {\r\n        return createFile(fileName, null);\r\n    }\r\n\r\n    /**\r\n     * Create a file and open it for reading and writing.\r\n     * You can specify the default attributes of the file (the server may or may\r\n     * not respect your wishes).\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param attr     may be <code>null</code> to use server defaults. Probably only\r\n     *                 the <code>uid</code>, <code>gid</code> and <code>permissions</code>\r\n     *                 (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle}\r\n     *                 structure make sense. You need only to set those fields where you want\r\n     *                 to override the server's defaults.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle createFile(String fileName, SFTPv3FileAttributes attr) throws IOException {\r\n        return openFile(fileName, 0x00000008 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_READ | SSH_FXF_WRITE\r\n    }\r\n\r\n    /**\r\n     * Create a file (truncate it if it already exists) and open it for reading and writing.\r\n     * Same as {@link #createFileTruncate(String, SFTPv3FileAttributes) createFileTruncate(fileName, null)}.\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle createFileTruncate(String fileName) throws IOException {\r\n        return createFileTruncate(fileName, null);\r\n    }\r\n\r\n    /**\r\n     * reate a file (truncate it if it already exists) and open it for reading and writing.\r\n     * You can specify the default attributes of the file (the server may or may\r\n     * not respect your wishes).\r\n     *\r\n     * @param fileName See the {@link SFTPv3Client comment} for the class for more details.\r\n     * @param attr     may be <code>null</code> to use server defaults. Probably only\r\n     *                 the <code>uid</code>, <code>gid</code> and <code>permissions</code>\r\n     *                 (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle}\r\n     *                 structure make sense. You need only to set those fields where you want\r\n     *                 to override the server's defaults.\r\n     * @return a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public SFTPv3FileHandle createFileTruncate(String fileName, SFTPv3FileAttributes attr) throws IOException {\r\n        return openFile(fileName, 0x00000018 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_TRUNC | SSH_FXF_READ | SSH_FXF_WRITE\r\n    }\r\n\r\n    private byte[] createAttrs(SFTPv3FileAttributes attr) {\r\n        TypesWriter tw = new TypesWriter();\r\n\r\n        int attrFlags = 0;\r\n\r\n        if (attr == null) {\r\n            tw.writeUINT32(0);\r\n        } else {\r\n            if (attr.size != null)\r\n                attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_SIZE;\r\n\r\n            if ((attr.uid != null) && (attr.gid != null))\r\n                attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID;\r\n\r\n            if (attr.permissions != null)\r\n                attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS;\r\n\r\n            if ((attr.atime != null) && (attr.mtime != null))\r\n                attrFlags = attrFlags | AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME;\r\n\r\n            tw.writeUINT32(attrFlags);\r\n\r\n            if (attr.size != null)\r\n                tw.writeUINT64(attr.size.longValue());\r\n\r\n            if ((attr.uid != null) && (attr.gid != null)) {\r\n                tw.writeUINT32(attr.uid.intValue());\r\n                tw.writeUINT32(attr.gid.intValue());\r\n            }\r\n\r\n            if (attr.permissions != null)\r\n                tw.writeUINT32(attr.permissions.intValue());\r\n\r\n            if ((attr.atime != null) && (attr.mtime != null)) {\r\n                tw.writeUINT32(attr.atime.intValue());\r\n                tw.writeUINT32(attr.mtime.intValue());\r\n            }\r\n        }\r\n\r\n        return tw.getBytes();\r\n    }\r\n\r\n    private SFTPv3FileHandle openFile(String fileName, int flags, SFTPv3FileAttributes attr) throws IOException {\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(fileName, charsetName);\r\n        tw.writeUINT32(flags);\r\n        tw.writeBytes(createAttrs(attr));\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_OPEN...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_OPEN, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_HANDLE) {\r\n            if (debug != null) {\r\n                debug.println(\"Got SSH_FXP_HANDLE.\");\r\n                debug.flush();\r\n            }\r\n\r\n            return new SFTPv3FileHandle(this, tr.readByteString());\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n        String errorMessage = tr.readString();\r\n\r\n        throw new SFTPException(errorMessage, errorCode);\r\n    }\r\n\r\n    /**\r\n     * Read bytes from a file. No more than 32768 bytes may be read at once.\r\n     * Be aware that the semantics of read() are different than for Java streams.\r\n     * <p>\r\n     * <ul>\r\n     * <li>The server will read as many bytes as it can from the file (up to <code>len</code>),\r\n     * and return them.</li>\r\n     * <li>If EOF is encountered before reading any data, <code>-1</code> is returned.\r\n     * <li>If an error occurs, an exception is thrown</li>.\r\n     * <li>For normal disk files, it is guaranteed that the server will return the specified\r\n     * number of bytes, or up to end of file. For, e.g., device files this may return\r\n     * fewer bytes than requested.</li>\r\n     * </ul>\r\n     *\r\n     * @param handle     a SFTPv3FileHandle handle\r\n     * @param fileOffset offset (in bytes) in the file\r\n     * @param dst        the destination byte array\r\n     * @param dstoff     offset in the destination byte array\r\n     * @param len        how many bytes to read, 0 &lt; len &lt;= 32768 bytes\r\n     * @return the number of bytes that could be read, may be less than requested if\r\n     * the end of the file is reached, -1 is returned in case of <code>EOF</code>\r\n     * @throws IOException\r\n     */\r\n    public int read(SFTPv3FileHandle handle, long fileOffset, byte[] dst, int dstoff, int len) throws IOException {\r\n        checkHandleValidAndOpen(handle);\r\n\r\n        if ((len > 32768) || (len <= 0))\r\n            throw new IllegalArgumentException(\"invalid len argument\");\r\n\r\n        int req_id = generateNextRequestID();\r\n\r\n        TypesWriter tw = new TypesWriter();\r\n        tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);\r\n        tw.writeUINT64(fileOffset);\r\n        tw.writeUINT32(len);\r\n\r\n        if (debug != null) {\r\n            debug.println(\"Sending SSH_FXP_READ...\");\r\n            debug.flush();\r\n        }\r\n\r\n        sendMessage(Packet.SSH_FXP_READ, req_id, tw.getBytes());\r\n\r\n        byte[] resp = receiveMessage(34000);\r\n\r\n        TypesReader tr = new TypesReader(resp);\r\n\r\n        int t = tr.readByte();\r\n\r\n        int rep_id = tr.readUINT32();\r\n        if (rep_id != req_id)\r\n            throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n        if (t == Packet.SSH_FXP_DATA) {\r\n            if (debug != null) {\r\n                debug.println(\"Got SSH_FXP_DATA...\");\r\n                debug.flush();\r\n            }\r\n\r\n            int readLen = tr.readUINT32();\r\n\r\n            if ((readLen < 0) || (readLen > len))\r\n                throw new IOException(\"The server sent an invalid length field.\");\r\n\r\n            tr.readBytes(dst, dstoff, readLen);\r\n\r\n            return readLen;\r\n        }\r\n\r\n        if (t != Packet.SSH_FXP_STATUS)\r\n            throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n        int errorCode = tr.readUINT32();\r\n\r\n        if (errorCode == ErrorCodes.SSH_FX_EOF) {\r\n            if (debug != null) {\r\n                debug.println(\"Got SSH_FX_EOF.\");\r\n                debug.flush();\r\n            }\r\n\r\n            return -1;\r\n        }\r\n\r\n        String errorMessage = tr.readString();\r\n\r\n        throw new SFTPException(errorMessage, errorCode);\r\n    }\r\n\r\n    /**\r\n     * Write bytes to a file. If <code>len</code> &gt; 32768, then the write operation will\r\n     * be split into multiple writes.\r\n     *\r\n     * @param handle     a SFTPv3FileHandle handle.\r\n     * @param fileOffset offset (in bytes) in the file.\r\n     * @param src        the source byte array.\r\n     * @param srcoff     offset in the source byte array.\r\n     * @param len        how many bytes to write.\r\n     * @throws IOException\r\n     */\r\n    public void write(SFTPv3FileHandle handle, long fileOffset, byte[] src, int srcoff, int len) throws IOException {\r\n        checkHandleValidAndOpen(handle);\r\n\r\n        if (len < 0)\r\n\r\n            while (len > 0) {\r\n                int writeRequestLen = len;\r\n\r\n                if (writeRequestLen > 32768)\r\n                    writeRequestLen = 32768;\r\n\r\n                int req_id = generateNextRequestID();\r\n\r\n                TypesWriter tw = new TypesWriter();\r\n                tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);\r\n                tw.writeUINT64(fileOffset);\r\n                tw.writeString(src, srcoff, writeRequestLen);\r\n\r\n                if (debug != null) {\r\n                    debug.println(\"Sending SSH_FXP_WRITE...\");\r\n                    debug.flush();\r\n                }\r\n\r\n                sendMessage(Packet.SSH_FXP_WRITE, req_id, tw.getBytes());\r\n\r\n                fileOffset += writeRequestLen;\r\n\r\n                srcoff += writeRequestLen;\r\n                len -= writeRequestLen;\r\n\r\n                byte[] resp = receiveMessage(34000);\r\n\r\n                TypesReader tr = new TypesReader(resp);\r\n\r\n                int t = tr.readByte();\r\n\r\n                int rep_id = tr.readUINT32();\r\n                if (rep_id != req_id)\r\n                    throw new IOException(\"The server sent an invalid id field.\");\r\n\r\n                if (t != Packet.SSH_FXP_STATUS)\r\n                    throw new IOException(\"The SFTP server sent an unexpected packet type (\" + t + \")\");\r\n\r\n                int errorCode = tr.readUINT32();\r\n\r\n                if (errorCode == ErrorCodes.SSH_FX_OK)\r\n                    continue;\r\n\r\n                String errorMessage = tr.readString();\r\n\r\n                throw new SFTPException(errorMessage, errorCode);\r\n            }\r\n    }\r\n\r\n    /**\r\n     * Close a file.\r\n     *\r\n     * @param handle a SFTPv3FileHandle handle\r\n     * @throws IOException\r\n     */\r\n    public void closeFile(SFTPv3FileHandle handle) throws IOException {\r\n        if (handle == null)\r\n            throw new IllegalArgumentException(\"the handle argument may not be null\");\r\n\r\n        try {\r\n            if (handle.isClosed == false) {\r\n                closeHandle(handle.fileHandle);\r\n            }\r\n        } finally {\r\n            handle.isClosed = true;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SFTPv3DirectoryEntry.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>SFTPv3DirectoryEntry</code> as returned by {@link SFTPv3Client#ls(String)}.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SFTPv3DirectoryEntry.java,v 1.2 2006/08/18 22:26:35 cplattne Exp $\r\n */\r\n\r\npublic class SFTPv3DirectoryEntry {\r\n    /**\r\n     * A relative name within the directory, without any path components.\r\n     */\r\n    public String filename;\r\n\r\n    /**\r\n     * An expanded format for the file name, similar to what is returned by\r\n     * \"ls -l\" on Un*x systems.\r\n     * <p>\r\n     * The format of this field is unspecified by the SFTP v3 protocol.\r\n     * It MUST be suitable for use in the output of a directory listing\r\n     * command (in fact, the recommended operation for a directory listing\r\n     * command is to simply display this data).  However, clients SHOULD NOT\r\n     * attempt to parse the longname field for file attributes; they SHOULD\r\n     * use the attrs field instead.\r\n     * <p>\r\n     * The recommended format for the longname field is as follows:<br>\r\n     * <code>-rwxr-xr-x   1 mjos     staff      348911 Mar 25 14:29 t-filexfer</code>\r\n     */\r\n    public String longEntry;\r\n\r\n    /**\r\n     * The attributes of this entry.\r\n     */\r\n    public SFTPv3FileAttributes attributes;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SFTPv3FileAttributes.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>SFTPv3FileAttributes</code> object represents detail information\r\n * about a file on the server. Not all fields may/must be present.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SFTPv3FileAttributes.java,v 1.3 2006/09/04 07:41:46 cplattne Exp $\r\n */\r\n\r\npublic class SFTPv3FileAttributes {\r\n    /**\r\n     * The SIZE attribute. <code>NULL</code> if not present.\r\n     */\r\n    public Long size = null;\r\n\r\n    /**\r\n     * The UID attribute. <code>NULL</code> if not present.\r\n     */\r\n    public Integer uid = null;\r\n\r\n    /**\r\n     * The GID attribute. <code>NULL</code> if not present.\r\n     */\r\n    public Integer gid = null;\r\n\r\n    /**\r\n     * The POSIX permissions. <code>NULL</code> if not present.\r\n     * <p>\r\n     * Here is a list:\r\n     * <p>\r\n     * <pre>Note: these numbers are all OCTAL.\r\n     *\r\n     *  S_IFMT     0170000   bitmask for the file type bitfields\r\n     *  S_IFSOCK   0140000   socket\r\n     *  S_IFLNK    0120000   symbolic link\r\n     *  S_IFREG    0100000   regular file\r\n     *  S_IFBLK    0060000   block device\r\n     *  S_IFDIR    0040000   directory\r\n     *  S_IFCHR    0020000   character device\r\n     *  S_IFIFO    0010000   fifo\r\n     *  S_ISUID    0004000   set UID bit\r\n     *  S_ISGID    0002000   set GID bit\r\n     *  S_ISVTX    0001000   sticky bit\r\n     *\r\n     *  S_IRWXU    00700     mask for file owner permissions\r\n     *  S_IRUSR    00400     owner has read permission\r\n     *  S_IWUSR    00200     owner has write permission\r\n     *  S_IXUSR    00100     owner has execute permission\r\n     *  S_IRWXG    00070     mask for group permissions\r\n     *  S_IRGRP    00040     group has read permission\r\n     *  S_IWGRP    00020     group has write permission\r\n     *  S_IXGRP    00010     group has execute permission\r\n     *  S_IRWXO    00007     mask for permissions for others (not in group)\r\n     *  S_IROTH    00004     others have read permission\r\n     *  S_IWOTH    00002     others have write permisson\r\n     *  S_IXOTH    00001     others have execute permission\r\n     * </pre>\r\n     */\r\n    public Integer permissions = null;\r\n\r\n    /**\r\n     * The ATIME attribute. Represented as seconds from Jan 1, 1970 in UTC.\r\n     * <code>NULL</code> if not present.\r\n     */\r\n    public Integer atime = null;\r\n\r\n    /**\r\n     * The MTIME attribute. Represented as seconds from Jan 1, 1970 in UTC.\r\n     * <code>NULL</code> if not present.\r\n     */\r\n    public Integer mtime = null;\r\n\r\n    /**\r\n     * Checks if this entry is a directory.\r\n     *\r\n     * @return Returns true if permissions are available and they indicate\r\n     * that this entry represents a directory.\r\n     */\r\n    public boolean isDirectory() {\r\n        if (permissions == null)\r\n            return false;\r\n\r\n        return ((permissions.intValue() & 0040000) != 0);\r\n    }\r\n\r\n    /**\r\n     * Checks if this entry is a regular file.\r\n     *\r\n     * @return Returns true if permissions are available and they indicate\r\n     * that this entry represents a regular file.\r\n     */\r\n    public boolean isRegularFile() {\r\n        if (permissions == null)\r\n            return false;\r\n\r\n        return ((permissions.intValue() & 0100000) != 0);\r\n    }\r\n\r\n    /**\r\n     * Checks if this entry is a a symlink.\r\n     *\r\n     * @return Returns true if permissions are available and they indicate\r\n     * that this entry represents a symlink.\r\n     */\r\n    public boolean isSymlink() {\r\n        if (permissions == null)\r\n            return false;\r\n\r\n        return ((permissions.intValue() & 0120000) != 0);\r\n    }\r\n\r\n    /**\r\n     * Turn the POSIX permissions into a 7 digit octal representation.\r\n     * Note: the returned value is first masked with <code>0177777</code>.\r\n     *\r\n     * @return <code>NULL</code> if permissions are not available.\r\n     */\r\n    public String getOctalPermissions() {\r\n        if (permissions == null)\r\n            return null;\r\n\r\n        String res = Integer.toString(permissions.intValue() & 0177777, 8);\r\n\r\n        StringBuffer sb = new StringBuffer();\r\n\r\n        int leadingZeros = 7 - res.length();\r\n\r\n        while (leadingZeros > 0) {\r\n            sb.append('0');\r\n            leadingZeros--;\r\n        }\r\n\r\n        sb.append(res);\r\n\r\n        return sb.toString();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/SFTPv3FileHandle.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A <code>SFTPv3FileHandle</code>.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SFTPv3FileHandle.java,v 1.2 2006/09/11 09:05:11 cplattne Exp $\r\n */\r\n\r\npublic class SFTPv3FileHandle {\r\n    final SFTPv3Client client;\r\n    final byte[] fileHandle;\r\n    boolean isClosed = false;\r\n\r\n\t/* The constructor is NOT public */\r\n\r\n    SFTPv3FileHandle(SFTPv3Client client, byte[] h) {\r\n        this.client = client;\r\n        this.fileHandle = h;\r\n    }\r\n\r\n    /**\r\n     * Get the SFTPv3Client instance which created this handle.\r\n     *\r\n     * @return A SFTPv3Client instance.\r\n     */\r\n    public SFTPv3Client getClient() {\r\n        return client;\r\n    }\r\n\r\n    /**\r\n     * Check if this handle was closed with the {@link SFTPv3Client#closeFile(SFTPv3FileHandle)} method\r\n     * of the <code>SFTPv3Client</code> instance which created the handle.\r\n     *\r\n     * @return if the handle is closed.\r\n     */\r\n    public boolean isClosed() {\r\n        return isClosed;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/ServerHostKeyVerifier.java",
    "content": "package ch.ethz.ssh2;\r\n\r\n/**\r\n * A callback interface used to implement a client specific method of checking\r\n * server host keys.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ServerHostKeyVerifier.java,v 1.4 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\n\r\npublic interface ServerHostKeyVerifier {\r\n    /**\r\n     * The actual verifier method, it will be called by the key exchange code\r\n     * on EVERY key exchange - this can happen several times during the lifetime\r\n     * of a connection.\r\n     * <p>\r\n     * Note: SSH-2 servers are allowed to change their hostkey at ANY time.\r\n     *\r\n     * @param hostname               the hostname used to create the {@link Connection} object\r\n     * @param port                   the remote TCP port\r\n     * @param serverHostKeyAlgorithm the public key algorithm (<code>ssh-rsa</code> or <code>ssh-dss</code>)\r\n     * @param serverHostKey          the server's public key blob\r\n     * @return if the client wants to accept the server's host key - if not, the\r\n     * connection will be closed.\r\n     * @throws Exception Will be wrapped with an IOException, extended version of returning false =)\r\n     */\r\n    public boolean verifyServerHostKey(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey)\r\n            throws Exception;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/Session.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport ch.ethz.ssh2.channel.Channel;\r\nimport ch.ethz.ssh2.channel.ChannelManager;\r\nimport ch.ethz.ssh2.channel.X11ServerData;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * A <code>Session</code> is a remote execution of a program. \"Program\" means\r\n * in this context either a shell, an application or a system command. The\r\n * program may or may not have a tty. Only one single program can be started on\r\n * a session. However, multiple sessions can be active simultaneously.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Session.java,v 1.9 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\npublic class Session {\r\n    final SecureRandom rnd;\r\n    ChannelManager cm;\r\n    Channel cn;\r\n    boolean flag_pty_requested = false;\r\n    boolean flag_x11_requested = false;\r\n    boolean flag_execution_started = false;\r\n    boolean flag_closed = false;\r\n    String x11FakeCookie = null;\r\n\r\n    Session(ChannelManager cm, SecureRandom rnd) throws IOException {\r\n        this.cm = cm;\r\n        this.cn = cm.openSessionChannel();\r\n        this.rnd = rnd;\r\n    }\r\n\r\n    /**\r\n     * Basically just a wrapper for lazy people - identical to calling\r\n     * <code>requestPTY(\"dumb\", 0, 0, 0, 0, null)</code>.\r\n     *\r\n     * @throws IOException\r\n     */\r\n    public void requestDumbPTY() throws IOException {\r\n        requestPTY(\"dumb\", 0, 0, 0, 0, null);\r\n    }\r\n\r\n    /**\r\n     * Basically just another wrapper for lazy people - identical to calling\r\n     * <code>requestPTY(term, 0, 0, 0, 0, null)</code>.\r\n     *\r\n     * @throws IOException\r\n     */\r\n    public void requestPTY(String term) throws IOException {\r\n        requestPTY(term, 0, 0, 0, 0, null);\r\n    }\r\n\r\n    /**\r\n     * Allocate a pseudo-terminal for this session.\r\n     * <p>\r\n     * This method may only be called before a program or shell is started in\r\n     * this session.\r\n     * <p>\r\n     * Different aspects can be specified:\r\n     * <p>\r\n     * <ul>\r\n     * <li>The TERM environment variable value (e.g., vt100)</li>\r\n     * <li>The terminal's dimensions.</li>\r\n     * <li>The encoded terminal modes.</li>\r\n     * </ul>\r\n     * Zero dimension parameters are ignored. The character/row dimensions\r\n     * override the pixel dimensions (when nonzero). Pixel dimensions refer to\r\n     * the drawable area of the window. The dimension parameters are only\r\n     * informational. The encoding of terminal modes (parameter\r\n     * <code>terminal_modes</code>) is described, e.g., in\r\n     * draft-ietf-secsh-connect-XY.txt.\r\n     *\r\n     * @param term                   The TERM environment variable value (e.g., vt100)\r\n     * @param term_width_characters  terminal width, characters (e.g., 80)\r\n     * @param term_height_characters terminal height, rows (e.g., 24)\r\n     * @param term_width_pixels      terminal width, pixels (e.g., 640)\r\n     * @param term_height_pixels     terminal height, pixels (e.g., 480)\r\n     * @param terminal_modes         encoded terminal modes (may be <code>null</code>)\r\n     * @throws IOException\r\n     */\r\n    public void requestPTY(String term, int term_width_characters, int term_height_characters, int term_width_pixels,\r\n                           int term_height_pixels, byte[] terminal_modes) throws IOException {\r\n        if (term == null)\r\n            throw new IllegalArgumentException(\"TERM cannot be null.\");\r\n\r\n        if ((terminal_modes != null) && (terminal_modes.length > 0)) {\r\n            if (terminal_modes[terminal_modes.length - 1] != 0)\r\n                throw new IOException(\"Illegal terminal modes description, does not end in zero byte\");\r\n        } else\r\n            terminal_modes = new byte[]{0};\r\n\r\n        synchronized (this) {\r\n            /* The following is just a nicer error, we would catch it anyway later in the channel code */\r\n            if (flag_closed)\r\n                throw new IOException(\"This session is closed.\");\r\n\r\n            if (flag_pty_requested)\r\n                throw new IOException(\"A PTY was already requested.\");\r\n\r\n            if (flag_execution_started)\r\n                throw new IOException(\r\n                        \"Cannot request PTY at this stage anymore, a remote execution has already started.\");\r\n\r\n            flag_pty_requested = true;\r\n        }\r\n\r\n        cm.requestPTY(cn, term, term_width_characters, term_height_characters, term_width_pixels, term_height_pixels,\r\n                terminal_modes);\r\n    }\r\n\r\n    /**\r\n     * Request X11 forwarding for the current session.\r\n     * <p>\r\n     * You have to supply the name and port of your X-server.\r\n     * <p>\r\n     * This method may only be called before a program or shell is started in\r\n     * this session.\r\n     *\r\n     * @param hostname         the hostname of the real (target) X11 server (e.g., 127.0.0.1)\r\n     * @param port             the port of the real (target) X11 server (e.g., 6010)\r\n     * @param cookie           if non-null, then present this cookie to the real X11 server\r\n     * @param singleConnection if true, then the server is instructed to only forward one single\r\n     *                         connection, no more connections shall be forwarded after first, or after the session\r\n     *                         channel has been closed\r\n     * @throws IOException\r\n     */\r\n    public void requestX11Forwarding(String hostname, int port, byte[] cookie, boolean singleConnection)\r\n            throws IOException {\r\n        if (hostname == null)\r\n            throw new IllegalArgumentException(\"hostname argument may not be null\");\r\n\r\n        synchronized (this) {\r\n\t\t\t/* The following is just a nicer error, we would catch it anyway later in the channel code */\r\n            if (flag_closed)\r\n                throw new IOException(\"This session is closed.\");\r\n\r\n            if (flag_x11_requested)\r\n                throw new IOException(\"X11 forwarding was already requested.\");\r\n\r\n            if (flag_execution_started)\r\n                throw new IOException(\r\n                        \"Cannot request X11 forwarding at this stage anymore, a remote execution has already started.\");\r\n\r\n            flag_x11_requested = true;\r\n        }\r\n\r\n\t\t/* X11ServerData - used to store data about the target X11 server */\r\n\r\n        X11ServerData x11data = new X11ServerData();\r\n\r\n        x11data.hostname = hostname;\r\n        x11data.port = port;\r\n        x11data.x11_magic_cookie = cookie; /* if non-null, then present this cookie to the real X11 server */\r\n\r\n\t\t/* Generate fake cookie - this one is used between remote clients and the ganymed proxy */\r\n\r\n        byte[] fakeCookie = new byte[16];\r\n        String hexEncodedFakeCookie;\r\n\r\n\t\t/* Make sure that this fake cookie is unique for this connection */\r\n\r\n        while (true) {\r\n            rnd.nextBytes(fakeCookie);\r\n\r\n\t\t\t/* Generate also hex representation of fake cookie */\r\n\r\n            StringBuffer tmp = new StringBuffer(32);\r\n            for (int i = 0; i < fakeCookie.length; i++) {\r\n                String digit2 = Integer.toHexString(fakeCookie[i] & 0xff);\r\n                tmp.append((digit2.length() == 2) ? digit2 : \"0\" + digit2);\r\n            }\r\n            hexEncodedFakeCookie = tmp.toString();\r\n\r\n\t\t\t/* Well, yes, chances are low, but we want to be on the safe side */\r\n\r\n            if (cm.checkX11Cookie(hexEncodedFakeCookie) == null)\r\n                break;\r\n        }\r\n\r\n\t\t/* Ask for X11 forwarding */\r\n\r\n        cm.requestX11(cn, singleConnection, \"MIT-MAGIC-COOKIE-1\", hexEncodedFakeCookie, 0);\r\n\r\n\t\t/* OK, that went fine, get ready to accept X11 connections... */\r\n\t\t/* ... but only if the user has not called close() in the meantime =) */\r\n\r\n        synchronized (this) {\r\n            if (flag_closed == false) {\r\n                this.x11FakeCookie = hexEncodedFakeCookie;\r\n                cm.registerX11Cookie(hexEncodedFakeCookie, x11data);\r\n            }\r\n        }\r\n\r\n\t\t/* Now it is safe to start remote X11 programs */\r\n    }\r\n\r\n    /**\r\n     * Execute a command on the remote machine.\r\n     *\r\n     * @param cmd The command to execute on the remote host.\r\n     * @throws IOException\r\n     */\r\n    public void execCommand(String cmd) throws IOException {\r\n        if (cmd == null)\r\n            throw new IllegalArgumentException(\"cmd argument may not be null\");\r\n\r\n        synchronized (this) {\r\n\t\t\t/* The following is just a nicer error, we would catch it anyway later in the channel code */\r\n            if (flag_closed)\r\n                throw new IOException(\"This session is closed.\");\r\n\r\n            if (flag_execution_started)\r\n                throw new IOException(\"A remote execution has already started.\");\r\n\r\n            flag_execution_started = true;\r\n        }\r\n\r\n        cm.requestExecCommand(cn, cmd);\r\n    }\r\n\r\n    /**\r\n     * Start a shell on the remote machine.\r\n     *\r\n     * @throws IOException\r\n     */\r\n    public void startShell() throws IOException {\r\n        synchronized (this) {\r\n\t\t\t/* The following is just a nicer error, we would catch it anyway later in the channel code */\r\n            if (flag_closed)\r\n                throw new IOException(\"This session is closed.\");\r\n\r\n            if (flag_execution_started)\r\n                throw new IOException(\"A remote execution has already started.\");\r\n\r\n            flag_execution_started = true;\r\n        }\r\n\r\n        cm.requestShell(cn);\r\n    }\r\n\r\n    /**\r\n     * Start a subsystem on the remote machine.\r\n     * Unless you know what you are doing, you will never need this.\r\n     *\r\n     * @param name the name of the subsystem.\r\n     * @throws IOException\r\n     */\r\n    public void startSubSystem(String name) throws IOException {\r\n        if (name == null)\r\n            throw new IllegalArgumentException(\"name argument may not be null\");\r\n\r\n        synchronized (this) {\r\n\t\t\t/* The following is just a nicer error, we would catch it anyway later in the channel code */\r\n            if (flag_closed)\r\n                throw new IOException(\"This session is closed.\");\r\n\r\n            if (flag_execution_started)\r\n                throw new IOException(\"A remote execution has already started.\");\r\n\r\n            flag_execution_started = true;\r\n        }\r\n\r\n        cm.requestSubSystem(cn, name);\r\n    }\r\n\r\n    public InputStream getStdout() {\r\n        return cn.getStdoutStream();\r\n    }\r\n\r\n    public InputStream getStderr() {\r\n        return cn.getStderrStream();\r\n    }\r\n\r\n    public OutputStream getStdin() {\r\n        return cn.getStdinStream();\r\n    }\r\n\r\n    /**\r\n     * This method blocks until there is more data available on either the\r\n     * stdout or stderr InputStream of this <code>Session</code>. Very useful\r\n     * if you do not want to use two parallel threads for reading from the two\r\n     * InputStreams. One can also specify a timeout. NOTE: do NOT call this\r\n     * method if you use concurrent threads that operate on either of the two\r\n     * InputStreams of this <code>Session</code> (otherwise this method may\r\n     * block, even though more data is available).\r\n     *\r\n     * @param timeout The (non-negative) timeout in <code>ms</code>. <code>0</code> means no\r\n     *                timeout, the call may block forever.\r\n     * @return <ul>\r\n     * <li><code>0</code> if no more data will arrive.</li>\r\n     * <li><code>1</code> if more data is available.</li>\r\n     * <li><code>-1</code> if a timeout occurred.</li>\r\n     * </ul>\r\n     * @throws IOException\r\n     * @deprecated This method has been replaced with a much more powerful wait-for-condition\r\n     * interface and therefore acts only as a wrapper.\r\n     */\r\n    public int waitUntilDataAvailable(long timeout) throws IOException {\r\n        if (timeout < 0)\r\n            throw new IllegalArgumentException(\"timeout must not be negative!\");\r\n\r\n        int conditions = cm.waitForCondition(cn, timeout, ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA\r\n                | ChannelCondition.EOF);\r\n\r\n        if ((conditions & ChannelCondition.TIMEOUT) != 0)\r\n            return -1;\r\n\r\n        if ((conditions & (ChannelCondition.STDOUT_DATA | ChannelCondition.STDERR_DATA)) != 0)\r\n            return 1;\r\n\r\n\t\t/* Here we do not need to check separately for CLOSED, since CLOSED implies EOF */\r\n\r\n        if ((conditions & ChannelCondition.EOF) != 0)\r\n            return 0;\r\n\r\n        throw new IllegalStateException(\"Unexpected condition result (\" + conditions + \")\");\r\n    }\r\n\r\n    /**\r\n     * This method blocks until certain conditions hold true on the underlying SSH-2 channel.\r\n     * <p>\r\n     * This method returns as soon as one of the following happens:\r\n     * <ul>\r\n     * <li>at least of the specified conditions (see {@link ChannelCondition}) holds true</li>\r\n     * <li>timeout > 0 and a timeout occured (TIMEOUT will be set in result conditions)</a>\r\n     * <li>the underlying channel was closed (CLOSED will be set in result conditions)</a>\r\n     * </ul>\r\n     * <p>\r\n     * In any case, the result value contains ALL current conditions, which may be more\r\n     * than the specified condition set (i.e., never use the \"==\" operator to test for conditions\r\n     * in the bitmask, see also comments in {@link ChannelCondition}).\r\n     * <p>\r\n     * Note: do NOT call this method if you want to wait for STDOUT_DATA or STDERR_DATA and\r\n     * there are concurrent threads (e.g., StreamGobblers) that operate on either of the two\r\n     * InputStreams of this <code>Session</code> (otherwise this method may\r\n     * block, even though more data is available in the StreamGobblers).\r\n     *\r\n     * @param condition_set a bitmask based on {@link ChannelCondition} values\r\n     * @param timeout       non-negative timeout in ms, <code>0</code> means no timeout\r\n     * @return all bitmask specifying all current conditions that are true\r\n     */\r\n\r\n    public int waitForCondition(int condition_set, long timeout) {\r\n        if (timeout < 0)\r\n            throw new IllegalArgumentException(\"timeout must be non-negative!\");\r\n\r\n        return cm.waitForCondition(cn, timeout, condition_set);\r\n    }\r\n\r\n    /**\r\n     * Get the exit code/status from the remote command - if available. Be\r\n     * careful - not all server implementations return this value. It is\r\n     * generally a good idea to call this method only when all data from the\r\n     * remote side has been consumed (see also the <code<WaitForCondition</code> method).\r\n     *\r\n     * @return An <code>Integer</code> holding the exit code, or\r\n     * <code>null</code> if no exit code is (yet) available.\r\n     */\r\n    public Integer getExitStatus() {\r\n        return cn.getExitStatus();\r\n    }\r\n\r\n    /**\r\n     * Get the name of the signal by which the process on the remote side was\r\n     * stopped - if available and applicable. Be careful - not all server\r\n     * implementations return this value.\r\n     *\r\n     * @return An <code>String</code> holding the name of the signal, or\r\n     * <code>null</code> if the process exited normally or is still\r\n     * running (or if the server forgot to send this information).\r\n     */\r\n    public String getExitSignal() {\r\n        return cn.getExitSignal();\r\n    }\r\n\r\n    /**\r\n     * Close this session. NEVER forget to call this method to free up resources -\r\n     * even if you got an exception from one of the other methods (or when\r\n     * getting an Exception on the Input- or OutputStreams). Sometimes these other\r\n     * methods may throw an exception, saying that the underlying channel is\r\n     * closed (this can happen, e.g., if the other server sent a close message.)\r\n     * However, as long as you have not called the <code>close()</code>\r\n     * method, you may be wasting (local) resources.\r\n     */\r\n    public void close() {\r\n        synchronized (this) {\r\n            if (flag_closed)\r\n                return;\r\n\r\n            flag_closed = true;\r\n\r\n            if (x11FakeCookie != null)\r\n                cm.unRegisterX11Cookie(x11FakeCookie, true);\r\n\r\n            try {\r\n                cm.closeChannel(cn, \"Closed due to user request\", true);\r\n            } catch (IOException ignored) {\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/StreamGobbler.java",
    "content": "package ch.ethz.ssh2;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\n\r\n/**\r\n * A <code>StreamGobbler</code> is an InputStream that uses an internal worker\r\n * thread to constantly consume input from another InputStream. It uses a buffer\r\n * to store the consumed data. The buffer size is automatically adjusted, if needed.\r\n * <p>\r\n * This class is sometimes very convenient - if you wrap a session's STDOUT and STDERR\r\n * InputStreams with instances of this class, then you don't have to bother about\r\n * the shared window of STDOUT and STDERR in the low level SSH-2 protocol,\r\n * since all arriving data will be immediatelly consumed by the worker threads.\r\n * Also, as a side effect, the streams will be buffered (e.g., single byte\r\n * read() operations are faster).\r\n * <p>\r\n * Other SSH for Java libraries include this functionality by default in\r\n * their STDOUT and STDERR InputStream implementations, however, please be aware\r\n * that this approach has also a downside:\r\n * <p>\r\n * If you do not call the StreamGobbler's <code>read()</code> method often enough\r\n * and the peer is constantly sending huge amounts of data, then you will sooner or later\r\n * encounter a low memory situation due to the aggregated data (well, it also depends on the Java heap size).\r\n * Joe Average will like this class anyway - a paranoid programmer would never use such an approach.\r\n * <p>\r\n * The term \"StreamGobbler\" was taken from an article called \"When Runtime.exec() won't\",\r\n * see http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: StreamGobbler.java,v 1.4 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\n\r\npublic class StreamGobbler extends InputStream {\r\n    private InputStream is;\r\n    private GobblerThread t;\r\n    private Object synchronizer = new Object();\r\n    private boolean isEOF = false;\r\n    private boolean isClosed = false;\r\n    private IOException exception = null;\r\n    private byte[] buffer = new byte[2048];\r\n    private int read_pos = 0;\r\n    private int write_pos = 0;\r\n    public StreamGobbler(InputStream is) {\r\n        this.is = is;\r\n        t = new GobblerThread();\r\n        t.setDaemon(true);\r\n        t.start();\r\n    }\r\n\r\n    public int read() throws IOException {\r\n        synchronized (synchronizer) {\r\n            if (isClosed)\r\n                throw new IOException(\"This StreamGobbler is closed.\");\r\n\r\n            while (read_pos == write_pos) {\r\n                if (exception != null)\r\n                    throw exception;\r\n\r\n                if (isEOF)\r\n                    return -1;\r\n\r\n                try {\r\n                    synchronizer.wait();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n\r\n            int b = buffer[read_pos++] & 0xff;\r\n\r\n            return b;\r\n        }\r\n    }\r\n\r\n    public int available() throws IOException {\r\n        synchronized (synchronizer) {\r\n            if (isClosed)\r\n                throw new IOException(\"This StreamGobbler is closed.\");\r\n\r\n            return write_pos - read_pos;\r\n        }\r\n    }\r\n\r\n    public int read(byte[] b) throws IOException {\r\n        return read(b, 0, b.length);\r\n    }\r\n\r\n    public void close() throws IOException {\r\n        synchronized (synchronizer) {\r\n            if (isClosed)\r\n                return;\r\n            isClosed = true;\r\n            isEOF = true;\r\n            synchronizer.notifyAll();\r\n            is.close();\r\n        }\r\n    }\r\n\r\n    public int read(byte[] b, int off, int len) throws IOException {\r\n        if (b == null)\r\n            throw new NullPointerException();\r\n\r\n        if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length))\r\n            throw new IndexOutOfBoundsException();\r\n\r\n        if (len == 0)\r\n            return 0;\r\n\r\n        synchronized (synchronizer) {\r\n            if (isClosed)\r\n                throw new IOException(\"This StreamGobbler is closed.\");\r\n\r\n            while (read_pos == write_pos) {\r\n                if (exception != null)\r\n                    throw exception;\r\n\r\n                if (isEOF)\r\n                    return -1;\r\n\r\n                try {\r\n                    synchronizer.wait();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n\r\n            int avail = write_pos - read_pos;\r\n\r\n            avail = (avail > len) ? len : avail;\r\n\r\n            System.arraycopy(buffer, read_pos, b, off, avail);\r\n\r\n            read_pos += avail;\r\n\r\n            return avail;\r\n        }\r\n    }\r\n\r\n    class GobblerThread extends Thread {\r\n        public void run() {\r\n            byte[] buff = new byte[8192];\r\n\r\n            while (true) {\r\n                try {\r\n                    int avail = is.read(buff);\r\n\r\n                    synchronized (synchronizer) {\r\n                        if (avail <= 0) {\r\n                            isEOF = true;\r\n                            synchronizer.notifyAll();\r\n                            break;\r\n                        }\r\n\r\n                        int space_available = buffer.length - write_pos;\r\n\r\n                        if (space_available < avail) {\r\n                            /* compact/resize buffer */\r\n\r\n                            int unread_size = write_pos - read_pos;\r\n                            int need_space = unread_size + avail;\r\n\r\n                            byte[] new_buffer = buffer;\r\n\r\n                            if (need_space > buffer.length) {\r\n                                int inc = need_space / 3;\r\n                                inc = (inc < 256) ? 256 : inc;\r\n                                inc = (inc > 8192) ? 8192 : inc;\r\n                                new_buffer = new byte[need_space + inc];\r\n                            }\r\n\r\n                            if (unread_size > 0)\r\n                                System.arraycopy(buffer, read_pos, new_buffer, 0, unread_size);\r\n\r\n                            buffer = new_buffer;\r\n\r\n                            read_pos = 0;\r\n                            write_pos = unread_size;\r\n                        }\r\n\r\n                        System.arraycopy(buff, 0, buffer, write_pos, avail);\r\n                        write_pos += avail;\r\n\r\n                        synchronizer.notifyAll();\r\n                    }\r\n                } catch (IOException e) {\r\n                    synchronized (synchronizer) {\r\n                        exception = e;\r\n                        synchronizer.notifyAll();\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/auth/AuthenticationManager.java",
    "content": "package ch.ethz.ssh2.auth;\r\n\r\nimport ch.ethz.ssh2.InteractiveCallback;\r\nimport ch.ethz.ssh2.crypto.PEMDecoder;\r\nimport ch.ethz.ssh2.packets.*;\r\nimport ch.ethz.ssh2.signature.*;\r\nimport ch.ethz.ssh2.transport.MessageHandler;\r\nimport ch.ethz.ssh2.transport.TransportManager;\r\n\r\nimport java.io.IOException;\r\nimport java.security.SecureRandom;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * AuthenticationManager.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AuthenticationManager.java,v 1.14 2006/07/30 21:59:29 cplattne Exp $\r\n */\r\npublic class AuthenticationManager implements MessageHandler {\r\n    TransportManager tm;\r\n\r\n    Vector packets = new Vector();\r\n    boolean connectionClosed = false;\r\n\r\n    String banner;\r\n\r\n    String[] remainingMethods = null;\r\n    boolean isPartialSuccess = false;\r\n\r\n    boolean authenticated = false;\r\n    boolean initDone = false;\r\n\r\n    public AuthenticationManager(TransportManager tm) {\r\n        this.tm = tm;\r\n    }\r\n\r\n    boolean methodPossible(String methName) {\r\n        if (remainingMethods == null)\r\n            return false;\r\n\r\n        for (int i = 0; i < remainingMethods.length; i++) {\r\n            if (remainingMethods[i].compareTo(methName) == 0)\r\n                return true;\r\n        }\r\n        return false;\r\n    }\r\n\r\n    byte[] deQueue() throws IOException {\r\n        synchronized (packets) {\r\n            while (packets.size() == 0) {\r\n                if (connectionClosed)\r\n                    throw (IOException) new IOException(\"The connection is closed.\").initCause(tm\r\n                            .getReasonClosedCause());\r\n\r\n                try {\r\n                    packets.wait();\r\n                } catch (InterruptedException ign) {\r\n                }\r\n            }\r\n            /* This sequence works with J2ME */\r\n            byte[] res = (byte[]) packets.firstElement();\r\n            packets.removeElementAt(0);\r\n            return res;\r\n        }\r\n    }\r\n\r\n    byte[] getNextMessage() throws IOException {\r\n        while (true) {\r\n            byte[] msg = deQueue();\r\n\r\n            if (msg[0] != Packets.SSH_MSG_USERAUTH_BANNER)\r\n                return msg;\r\n\r\n            PacketUserauthBanner sb = new PacketUserauthBanner(msg, 0, msg.length);\r\n\r\n            banner = sb.getBanner();\r\n        }\r\n    }\r\n\r\n    public String[] getRemainingMethods(String user) throws IOException {\r\n        initialize(user);\r\n        return remainingMethods;\r\n    }\r\n\r\n    public boolean getPartialSuccess() {\r\n        return isPartialSuccess;\r\n    }\r\n\r\n    private boolean initialize(String user) throws IOException {\r\n        if (initDone == false) {\r\n            tm.registerMessageHandler(this, 0, 255);\r\n\r\n            PacketServiceRequest sr = new PacketServiceRequest(\"ssh-userauth\");\r\n            tm.sendMessage(sr.getPayload());\r\n\r\n            PacketUserauthRequestNone urn = new PacketUserauthRequestNone(\"ssh-connection\", user);\r\n            tm.sendMessage(urn.getPayload());\r\n\r\n            byte[] msg = getNextMessage();\r\n            new PacketServiceAccept(msg, 0, msg.length);\r\n            msg = getNextMessage();\r\n\r\n            initDone = true;\r\n\r\n            if (msg[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) {\r\n                authenticated = true;\r\n                return true;\r\n            }\r\n\r\n            if (msg[0] == Packets.SSH_MSG_USERAUTH_FAILURE) {\r\n                PacketUserauthFailure puf = new PacketUserauthFailure(msg, 0, msg.length);\r\n\r\n                remainingMethods = puf.getAuthThatCanContinue();\r\n                isPartialSuccess = puf.isPartialSuccess();\r\n                return false;\r\n            }\r\n\r\n            throw new IOException(\"Unexpected SSH message (type \" + msg[0] + \")\");\r\n        }\r\n        return authenticated;\r\n    }\r\n\r\n    public boolean authenticatePublicKey(String user, char[] PEMPrivateKey, String password, SecureRandom rnd) throws IOException {\r\n        try {\r\n            initialize(user);\r\n\r\n            if (methodPossible(\"publickey\") == false)\r\n                throw new IOException(\"Authentication method publickey not supported by the server at this stage.\");\r\n\r\n            Object key = PEMDecoder.decode(PEMPrivateKey, password);\r\n\r\n            if (key instanceof DSAPrivateKey) {\r\n                DSAPrivateKey pk = (DSAPrivateKey) key;\r\n\r\n                byte[] pk_enc = DSASHA1Verify.encodeSSHDSAPublicKey(pk.getPublicKey());\r\n\r\n                TypesWriter tw = new TypesWriter();\r\n\r\n                byte[] H = tm.getSessionIdentifier();\r\n\r\n                tw.writeString(H, 0, H.length);\r\n                tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n                tw.writeString(user);\r\n                tw.writeString(\"ssh-connection\");\r\n                tw.writeString(\"publickey\");\r\n                tw.writeBoolean(true);\r\n                tw.writeString(\"ssh-dss\");\r\n                tw.writeString(pk_enc, 0, pk_enc.length);\r\n\r\n                byte[] msg = tw.getBytes();\r\n\r\n                DSASignature ds = DSASHA1Verify.generateSignature(msg, pk, rnd);\r\n\r\n                byte[] ds_enc = DSASHA1Verify.encodeSSHDSASignature(ds);\r\n\r\n                PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey(\"ssh-connection\", user,\r\n                        \"ssh-dss\", pk_enc, ds_enc);\r\n                tm.sendMessage(ua.getPayload());\r\n            } else if (key instanceof RSAPrivateKey) {\r\n                RSAPrivateKey pk = (RSAPrivateKey) key;\r\n\r\n                byte[] pk_enc = RSASHA1Verify.encodeSSHRSAPublicKey(pk.getPublicKey());\r\n\r\n                TypesWriter tw = new TypesWriter();\r\n                {\r\n                    byte[] H = tm.getSessionIdentifier();\r\n\r\n                    tw.writeString(H, 0, H.length);\r\n                    tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n                    tw.writeString(user);\r\n                    tw.writeString(\"ssh-connection\");\r\n                    tw.writeString(\"publickey\");\r\n                    tw.writeBoolean(true);\r\n                    tw.writeString(\"ssh-rsa\");\r\n                    tw.writeString(pk_enc, 0, pk_enc.length);\r\n                }\r\n\r\n                byte[] msg = tw.getBytes();\r\n\r\n                RSASignature ds = RSASHA1Verify.generateSignature(msg, pk);\r\n\r\n                byte[] rsa_sig_enc = RSASHA1Verify.encodeSSHRSASignature(ds);\r\n\r\n                PacketUserauthRequestPublicKey ua = new PacketUserauthRequestPublicKey(\"ssh-connection\", user,\r\n                        \"ssh-rsa\", pk_enc, rsa_sig_enc);\r\n                tm.sendMessage(ua.getPayload());\r\n            } else {\r\n                throw new IOException(\"Unknown private key type returned by the PEM decoder.\");\r\n            }\r\n\r\n            byte[] ar = getNextMessage();\r\n\r\n            if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) {\r\n                authenticated = true;\r\n                tm.removeMessageHandler(this, 0, 255);\r\n                return true;\r\n            }\r\n\r\n            if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) {\r\n                PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);\r\n\r\n                remainingMethods = puf.getAuthThatCanContinue();\r\n                isPartialSuccess = puf.isPartialSuccess();\r\n\r\n                return false;\r\n            }\r\n\r\n            throw new IOException(\"Unexpected SSH message (type \" + ar[0] + \")\");\r\n\r\n        } catch (IOException e) {\r\n            tm.close(e, false);\r\n            throw (IOException) new IOException(\"Publickey authentication failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public boolean authenticatePassword(String user, String pass) throws IOException {\r\n        try {\r\n            initialize(user);\r\n\r\n            if (methodPossible(\"password\") == false)\r\n                throw new IOException(\"Authentication method password not supported by the server at this stage.\");\r\n\r\n            PacketUserauthRequestPassword ua = new PacketUserauthRequestPassword(\"ssh-connection\", user, pass);\r\n            tm.sendMessage(ua.getPayload());\r\n\r\n            byte[] ar = getNextMessage();\r\n\r\n            if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) {\r\n                authenticated = true;\r\n                tm.removeMessageHandler(this, 0, 255);\r\n                return true;\r\n            }\r\n\r\n            if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) {\r\n                PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);\r\n\r\n                remainingMethods = puf.getAuthThatCanContinue();\r\n                isPartialSuccess = puf.isPartialSuccess();\r\n\r\n                return false;\r\n            }\r\n\r\n            throw new IOException(\"Unexpected SSH message (type \" + ar[0] + \")\");\r\n\r\n        } catch (IOException e) {\r\n            tm.close(e, false);\r\n            throw (IOException) new IOException(\"Password authentication failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public boolean authenticateInteractive(String user, String[] submethods, InteractiveCallback cb) throws IOException {\r\n        try {\r\n            initialize(user);\r\n\r\n            if (methodPossible(\"keyboard-interactive\") == false)\r\n                throw new IOException(\r\n                        \"Authentication method keyboard-interactive not supported by the server at this stage.\");\r\n\r\n            if (submethods == null)\r\n                submethods = new String[0];\r\n\r\n            PacketUserauthRequestInteractive ua = new PacketUserauthRequestInteractive(\"ssh-connection\", user,\r\n                    submethods);\r\n\r\n            tm.sendMessage(ua.getPayload());\r\n\r\n            while (true) {\r\n                byte[] ar = getNextMessage();\r\n\r\n                if (ar[0] == Packets.SSH_MSG_USERAUTH_SUCCESS) {\r\n                    authenticated = true;\r\n                    tm.removeMessageHandler(this, 0, 255);\r\n                    return true;\r\n                }\r\n\r\n                if (ar[0] == Packets.SSH_MSG_USERAUTH_FAILURE) {\r\n                    PacketUserauthFailure puf = new PacketUserauthFailure(ar, 0, ar.length);\r\n\r\n                    remainingMethods = puf.getAuthThatCanContinue();\r\n                    isPartialSuccess = puf.isPartialSuccess();\r\n\r\n                    return false;\r\n                }\r\n\r\n                if (ar[0] == Packets.SSH_MSG_USERAUTH_INFO_REQUEST) {\r\n                    PacketUserauthInfoRequest pui = new PacketUserauthInfoRequest(ar, 0, ar.length);\r\n\r\n                    String[] responses;\r\n\r\n                    try {\r\n                        responses = cb.replyToChallenge(pui.getName(), pui.getInstruction(), pui.getNumPrompts(), pui\r\n                                .getPrompt(), pui.getEcho());\r\n                    } catch (Exception e) {\r\n                        throw (IOException) new IOException(\"Exception in callback.\").initCause(e);\r\n                    }\r\n\r\n                    if (responses == null)\r\n                        throw new IOException(\"Your callback may not return NULL!\");\r\n\r\n                    PacketUserauthInfoResponse puir = new PacketUserauthInfoResponse(responses);\r\n                    tm.sendMessage(puir.getPayload());\r\n\r\n                    continue;\r\n                }\r\n\r\n                throw new IOException(\"Unexpected SSH message (type \" + ar[0] + \")\");\r\n            }\r\n        } catch (IOException e) {\r\n            tm.close(e, false);\r\n            throw (IOException) new IOException(\"Keyboard-interactive authentication failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void handleMessage(byte[] msg, int msglen) throws IOException {\r\n        synchronized (packets) {\r\n            if (msg == null) {\r\n                connectionClosed = true;\r\n            } else {\r\n                byte[] tmp = new byte[msglen];\r\n                System.arraycopy(msg, 0, tmp, 0, msglen);\r\n                packets.addElement(tmp);\r\n            }\r\n\r\n            packets.notifyAll();\r\n\r\n            if (packets.size() > 5) {\r\n                connectionClosed = true;\r\n                throw new IOException(\"Error, peer is flooding us with authentication packets.\");\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/Channel.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\n/**\r\n * Channel.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Channel.java,v 1.7 2005/12/07 10:25:48 cplattne Exp $\r\n */\r\npublic class Channel {\r\n    /*\r\n\t * OK. Here is an important part of the JVM Specification:\r\n\t * (http://java.sun.com/docs/books/vmspec/2nd-edition/html/Threads.doc.html#22214)\r\n\t * \r\n\t * Any association between locks and variables is purely conventional.\r\n\t * Locking any lock conceptually flushes all variables from a thread's\r\n\t * working memory, and unlocking any lock forces the writing out to main\r\n\t * memory of all variables that the thread has assigned. That a lock may be\r\n\t * associated with a particular object or a class is purely a convention.\r\n\t * (...)\r\n\t * \r\n\t * If a thread uses a particular shared variable only after locking a\r\n\t * particular lock and before the corresponding unlocking of that same lock,\r\n\t * then the thread will read the shared value of that variable from main\r\n\t * memory after the lock operation, if necessary, and will copy back to main\r\n\t * memory the value most recently assigned to that variable before the\r\n\t * unlock operation.\r\n\t * \r\n\t * This, in conjunction with the mutual exclusion rules for locks, suffices\r\n\t * to guarantee that values are correctly transmitted from one thread to\r\n\t * another through shared variables.\r\n\t * \r\n\t * ====> Always keep that in mind when modifying the Channel/ChannelManger\r\n\t * code.\r\n\t * \r\n\t */\r\n\r\n    static final int STATE_OPENING = 1;\r\n    static final int STATE_OPEN = 2;\r\n    static final int STATE_CLOSED = 4;\r\n\r\n    static final int CHANNEL_BUFFER_SIZE = 30000;\r\n\r\n\t/*\r\n\t * To achieve correctness, the following rules have to be respected when\r\n\t * accessing this object:\r\n\t */\r\n\r\n    // These fields can always be read\r\n    final ChannelManager cm;\r\n    final ChannelOutputStream stdinStream;\r\n    final ChannelInputStream stdoutStream;\r\n    final ChannelInputStream stderrStream;\r\n\r\n    // These two fields will only be written while the Channel is in state\r\n    // STATE_OPENING.\r\n    // The code makes sure that the two fields are written out when the state is\r\n    // changing to STATE_OPEN.\r\n    // Therefore, if you know that the Channel is in state STATE_OPEN, then you\r\n    // can read these two fields without synchronizing on the Channel. However, make\r\n    // sure that you get the latest values (e.g., flush caches by synchronizing on any\r\n    // object). However, to be on the safe side, you can lock the channel.\r\n    final Object channelSendLock = new Object();\r\n    final byte[] msgWindowAdjust = new byte[9];\r\n\r\n\t/*\r\n\t * Make sure that we never send a data/EOF/WindowChange msg after a CLOSE\r\n\t * msg.\r\n\t * \r\n\t * This is a little bit complicated, but we have to do it in that way, since\r\n\t * we cannot keep a lock on the Channel during the send operation (this\r\n\t * would block sometimes the receiver thread, and, in extreme cases, can\r\n\t * lead to a deadlock on both sides of the connection (senders are blocked\r\n\t * since the receive buffers on the other side are full, and receiver\r\n\t * threads wait for the senders to finish). It all depends on the\r\n\t * implementation on the other side. But we cannot make any assumptions, we\r\n\t * have to assume the worst case. Confused? Just believe me.\r\n\t */\r\n\r\n\t/*\r\n\t * If you send a message on a channel, then you have to aquire the\r\n\t * \"channelSendLock\" and check the \"closeMessageSent\" flag (this variable\r\n\t * may only be accessed while holding the \"channelSendLock\" !!!\r\n\t * \r\n\t * BTW: NEVER EVER SEND MESSAGES FROM THE RECEIVE THREAD - see explanation\r\n\t * above.\r\n\t */\r\n    final byte[] stdoutBuffer = new byte[CHANNEL_BUFFER_SIZE];\r\n    final byte[] stderrBuffer = new byte[CHANNEL_BUFFER_SIZE];\r\n\r\n\t/*\r\n\t * Stop memory fragmentation by allocating this often used buffer.\r\n\t * May only be used while holding the channelSendLock\r\n\t */\r\n    private final Object reasonClosedLock = new Object();\r\n\r\n    // If you access (read or write) any of the following fields, then you have\r\n    // to synchronize on the channel.\r\n    int localID = -1;\r\n    int remoteID = -1;\r\n    boolean closeMessageSent = false;\r\n    int state = STATE_OPENING;\r\n    boolean closeMessageRecv = false;\r\n    /* This is a stupid implementation. At the moment we can only wait\r\n     * for one pending request per channel.\r\n     */\r\n    int successCounter = 0;\r\n    int failedCounter = 0;\r\n    int localWindow = 0; /* locally, we use a small window, < 2^31 */\r\n    long remoteWindow = 0; /* long for readable  2^32 - 1 window support */\r\n    int localMaxPacketSize = -1;\r\n    int remoteMaxPacketSize = -1;\r\n    int stdoutReadpos = 0;\r\n    int stdoutWritepos = 0;\r\n    int stderrReadpos = 0;\r\n    int stderrWritepos = 0;\r\n    boolean EOF = false;\r\n    Integer exit_status;\r\n\r\n    // we keep the x11 cookie so that this channel can be closed when this\r\n    // specific x11 forwarding gets stopped\r\n    String exit_signal;\r\n\r\n    // reasonClosed is special, since we sometimes need to access it\r\n    // while holding the channelSendLock.\r\n    // We protect it with a private short term lock.\r\n    String hexX11FakeCookie;\r\n    private String reasonClosed = null;\r\n\r\n    public Channel(ChannelManager cm) {\r\n        this.cm = cm;\r\n\r\n        this.localWindow = CHANNEL_BUFFER_SIZE;\r\n        this.localMaxPacketSize = 35000 - 1024; // leave enough slack\r\n\r\n        this.stdinStream = new ChannelOutputStream(this);\r\n        this.stdoutStream = new ChannelInputStream(this, false);\r\n        this.stderrStream = new ChannelInputStream(this, true);\r\n    }\r\n\r\n\t/* Methods to allow access from classes outside of this package */\r\n\r\n    public ChannelInputStream getStderrStream() {\r\n        return stderrStream;\r\n    }\r\n\r\n    public ChannelOutputStream getStdinStream() {\r\n        return stdinStream;\r\n    }\r\n\r\n    public ChannelInputStream getStdoutStream() {\r\n        return stdoutStream;\r\n    }\r\n\r\n    public String getExitSignal() {\r\n        synchronized (this) {\r\n            return exit_signal;\r\n        }\r\n    }\r\n\r\n    public Integer getExitStatus() {\r\n        synchronized (this) {\r\n            return exit_status;\r\n        }\r\n    }\r\n\r\n    public String getReasonClosed() {\r\n        synchronized (reasonClosedLock) {\r\n            return reasonClosed;\r\n        }\r\n    }\r\n\r\n    public void setReasonClosed(String reasonClosed) {\r\n        synchronized (reasonClosedLock) {\r\n            if (this.reasonClosed == null)\r\n                this.reasonClosed = reasonClosed;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/ChannelInputStream.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\n\r\n/**\r\n * ChannelInputStream.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ChannelInputStream.java,v 1.5 2005/12/05 17:13:26 cplattne Exp $\r\n */\r\npublic final class ChannelInputStream extends InputStream {\r\n    Channel c;\r\n\r\n    boolean isClosed = false;\r\n    boolean isEOF = false;\r\n    boolean extendedFlag = false;\r\n\r\n    ChannelInputStream(Channel c, boolean isExtended) {\r\n        this.c = c;\r\n        this.extendedFlag = isExtended;\r\n    }\r\n\r\n    public int available() throws IOException {\r\n        if (isEOF)\r\n            return 0;\r\n\r\n        int avail = c.cm.getAvailable(c, extendedFlag);\r\n\r\n\t\t/* We must not return -1 on EOF */\r\n\r\n        return (avail > 0) ? avail : 0;\r\n    }\r\n\r\n    public void close() throws IOException {\r\n        isClosed = true;\r\n    }\r\n\r\n    public int read(byte[] b, int off, int len) throws IOException {\r\n        if (b == null)\r\n            throw new NullPointerException();\r\n\r\n        if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length))\r\n            throw new IndexOutOfBoundsException();\r\n\r\n        if (len == 0)\r\n            return 0;\r\n\r\n        if (isEOF)\r\n            return -1;\r\n\r\n        int ret = c.cm.getChannelData(c, extendedFlag, b, off, len);\r\n\r\n        if (ret == -1) {\r\n            isEOF = true;\r\n        }\r\n\r\n        return ret;\r\n    }\r\n\r\n    public int read(byte[] b) throws IOException {\r\n        return read(b, 0, b.length);\r\n    }\r\n\r\n    public int read() throws IOException {\r\n        /* Yes, this stream is pure and unbuffered, a single byte read() is slow */\r\n\r\n        final byte b[] = new byte[1];\r\n\r\n        int ret = read(b, 0, 1);\r\n\r\n        if (ret != 1)\r\n            return -1;\r\n\r\n        return b[0] & 0xff;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/ChannelManager.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport ch.ethz.ssh2.ChannelCondition;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.*;\r\nimport ch.ethz.ssh2.transport.MessageHandler;\r\nimport ch.ethz.ssh2.transport.TransportManager;\r\n\r\nimport java.io.IOException;\r\nimport java.util.HashMap;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * ChannelManager. Please read the comments in Channel.java.\r\n * <p>\r\n * Besides the crypto part, this is the core of the library.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ChannelManager.java,v 1.15 2006/08/11 12:24:01 cplattne Exp $\r\n */\r\npublic class ChannelManager implements MessageHandler {\r\n    private static final Logger log = Logger.getLogger(ChannelManager.class);\r\n\r\n    private HashMap x11_magic_cookies = new HashMap();\r\n\r\n    private TransportManager tm;\r\n\r\n    private Vector channels = new Vector();\r\n    private int nextLocalChannel = 100;\r\n    private boolean shutdown = false;\r\n    private int globalSuccessCounter = 0;\r\n    private int globalFailedCounter = 0;\r\n\r\n    private HashMap remoteForwardings = new HashMap();\r\n\r\n    private Vector listenerThreads = new Vector();\r\n\r\n    private boolean listenerThreadsAllowed = true;\r\n\r\n    public ChannelManager(TransportManager tm) {\r\n        this.tm = tm;\r\n        tm.registerMessageHandler(this, 80, 100);\r\n    }\r\n\r\n    private Channel getChannel(int id) {\r\n        synchronized (channels) {\r\n            for (int i = 0; i < channels.size(); i++) {\r\n                Channel c = (Channel) channels.elementAt(i);\r\n                if (c.localID == id)\r\n                    return c;\r\n            }\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private void removeChannel(int id) {\r\n        synchronized (channels) {\r\n            for (int i = 0; i < channels.size(); i++) {\r\n                Channel c = (Channel) channels.elementAt(i);\r\n                if (c.localID == id) {\r\n                    channels.removeElementAt(i);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    private int addChannel(Channel c) {\r\n        synchronized (channels) {\r\n            channels.addElement(c);\r\n            return nextLocalChannel++;\r\n        }\r\n    }\r\n\r\n    private void waitUntilChannelOpen(Channel c) throws IOException {\r\n        synchronized (c) {\r\n            while (c.state == Channel.STATE_OPENING) {\r\n                try {\r\n                    c.wait();\r\n                } catch (InterruptedException ignore) {\r\n                }\r\n            }\r\n\r\n            if (c.state != Channel.STATE_OPEN) {\r\n                removeChannel(c.localID);\r\n\r\n                String detail = c.getReasonClosed();\r\n\r\n                if (detail == null)\r\n                    detail = \"state: \" + c.state;\r\n\r\n                throw new IOException(\"Could not open channel (\" + detail + \")\");\r\n            }\r\n        }\r\n    }\r\n\r\n    private final void waitForGlobalSuccessOrFailure() throws IOException {\r\n        synchronized (channels) {\r\n            while ((globalSuccessCounter == 0) && (globalFailedCounter == 0)) {\r\n                if (shutdown) {\r\n                    throw new IOException(\"The connection is being shutdown\");\r\n                }\r\n\r\n                try {\r\n                    channels.wait();\r\n                } catch (InterruptedException ignore) {\r\n                }\r\n            }\r\n\r\n            if (globalFailedCounter != 0) {\r\n                throw new IOException(\"The server denied the request (did you enable port forwarding?)\");\r\n            }\r\n\r\n            if (globalSuccessCounter == 0) {\r\n                throw new IOException(\"Illegal state.\");\r\n            }\r\n\r\n        }\r\n    }\r\n\r\n    private final void waitForChannelSuccessOrFailure(Channel c) throws IOException {\r\n        synchronized (c) {\r\n            while ((c.successCounter == 0) && (c.failedCounter == 0)) {\r\n                if (c.state != Channel.STATE_OPEN) {\r\n                    String detail = c.getReasonClosed();\r\n\r\n                    if (detail == null)\r\n                        detail = \"state: \" + c.state;\r\n\r\n                    throw new IOException(\"This SSH2 channel is not open (\" + detail + \")\");\r\n                }\r\n\r\n                try {\r\n                    c.wait();\r\n                } catch (InterruptedException ignore) {\r\n                }\r\n            }\r\n\r\n            if (c.failedCounter != 0) {\r\n                throw new IOException(\"The server denied the request.\");\r\n            }\r\n        }\r\n    }\r\n\r\n    public void registerX11Cookie(String hexFakeCookie, X11ServerData data) {\r\n        synchronized (x11_magic_cookies) {\r\n            x11_magic_cookies.put(hexFakeCookie, data);\r\n        }\r\n    }\r\n\r\n    public void unRegisterX11Cookie(String hexFakeCookie, boolean killChannels) {\r\n        if (hexFakeCookie == null)\r\n            throw new IllegalStateException(\"hexFakeCookie may not be null\");\r\n\r\n        synchronized (x11_magic_cookies) {\r\n            x11_magic_cookies.remove(hexFakeCookie);\r\n        }\r\n\r\n        if (killChannels == false)\r\n            return;\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Closing all X11 channels for the given fake cookie\");\r\n\r\n        Vector channel_copy;\r\n\r\n        synchronized (channels) {\r\n            channel_copy = (Vector) channels.clone();\r\n        }\r\n\r\n        for (int i = 0; i < channel_copy.size(); i++) {\r\n            Channel c = (Channel) channel_copy.elementAt(i);\r\n\r\n            synchronized (c) {\r\n                if (hexFakeCookie.equals(c.hexX11FakeCookie) == false)\r\n                    continue;\r\n            }\r\n\r\n            try {\r\n                closeChannel(c, \"Closing X11 channel since the corresponding session is closing\", true);\r\n            } catch (IOException e) {\r\n            }\r\n        }\r\n    }\r\n\r\n    public X11ServerData checkX11Cookie(String hexFakeCookie) {\r\n        synchronized (x11_magic_cookies) {\r\n            if (hexFakeCookie != null)\r\n                return (X11ServerData) x11_magic_cookies.get(hexFakeCookie);\r\n        }\r\n        return null;\r\n    }\r\n\r\n    public void closeAllChannels() {\r\n        if (log.isEnabled())\r\n            log.log(50, \"Closing all channels\");\r\n\r\n        Vector channel_copy;\r\n\r\n        synchronized (channels) {\r\n            channel_copy = (Vector) channels.clone();\r\n        }\r\n\r\n        for (int i = 0; i < channel_copy.size(); i++) {\r\n            Channel c = (Channel) channel_copy.elementAt(i);\r\n            try {\r\n                closeChannel(c, \"Closing all channels\", true);\r\n            } catch (IOException e) {\r\n            }\r\n        }\r\n    }\r\n\r\n    public void closeChannel(Channel c, String reason, boolean force) throws IOException {\r\n        byte msg[] = new byte[5];\r\n\r\n        synchronized (c) {\r\n            if (force) {\r\n                c.state = Channel.STATE_CLOSED;\r\n                c.EOF = true;\r\n            }\r\n\r\n            c.setReasonClosed(reason);\r\n\r\n            msg[0] = Packets.SSH_MSG_CHANNEL_CLOSE;\r\n            msg[1] = (byte) (c.remoteID >> 24);\r\n            msg[2] = (byte) (c.remoteID >> 16);\r\n            msg[3] = (byte) (c.remoteID >> 8);\r\n            msg[4] = (byte) (c.remoteID);\r\n\r\n            c.notifyAll();\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent == true)\r\n                return;\r\n            tm.sendMessage(msg);\r\n            c.closeMessageSent = true;\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Sent SSH_MSG_CHANNEL_CLOSE (channel \" + c.localID + \")\");\r\n    }\r\n\r\n    public void sendEOF(Channel c) throws IOException {\r\n        byte[] msg = new byte[5];\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                return;\r\n\r\n            msg[0] = Packets.SSH_MSG_CHANNEL_EOF;\r\n            msg[1] = (byte) (c.remoteID >> 24);\r\n            msg[2] = (byte) (c.remoteID >> 16);\r\n            msg[3] = (byte) (c.remoteID >> 8);\r\n            msg[4] = (byte) (c.remoteID);\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent == true)\r\n                return;\r\n            tm.sendMessage(msg);\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Sent EOF (Channel \" + c.localID + \"/\" + c.remoteID + \")\");\r\n    }\r\n\r\n    public void sendOpenConfirmation(Channel c) throws IOException {\r\n        PacketChannelOpenConfirmation pcoc = null;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPENING)\r\n                return;\r\n\r\n            c.state = Channel.STATE_OPEN;\r\n\r\n            pcoc = new PacketChannelOpenConfirmation(c.remoteID, c.localID, c.localWindow, c.localMaxPacketSize);\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent == true)\r\n                return;\r\n            tm.sendMessage(pcoc.getPayload());\r\n        }\r\n    }\r\n\r\n    public void sendData(Channel c, byte[] buffer, int pos, int len) throws IOException {\r\n        while (len > 0) {\r\n            int thislen = 0;\r\n            byte[] msg;\r\n\r\n            synchronized (c) {\r\n                while (true) {\r\n                    if (c.state == Channel.STATE_CLOSED)\r\n                        throw new IOException(\"SSH channel is closed. (\" + c.getReasonClosed() + \")\");\r\n\r\n                    if (c.state != Channel.STATE_OPEN)\r\n                        throw new IOException(\"SSH channel in strange state. (\" + c.state + \")\");\r\n\r\n                    if (c.remoteWindow != 0)\r\n                        break;\r\n\r\n                    try {\r\n                        c.wait();\r\n                    } catch (InterruptedException ignore) {\r\n                    }\r\n                }\r\n\r\n\t\t\t\t/* len > 0, no sign extension can happen when comparing */\r\n\r\n                thislen = (c.remoteWindow >= len) ? len : (int) c.remoteWindow;\r\n\r\n                int estimatedMaxDataLen = c.remoteMaxPacketSize - (tm.getPacketOverheadEstimate() + 9);\r\n\r\n\t\t\t\t/* The worst case scenario =) a true bottleneck */\r\n\r\n                if (estimatedMaxDataLen <= 0) {\r\n                    estimatedMaxDataLen = 1;\r\n                }\r\n\r\n                if (thislen > estimatedMaxDataLen)\r\n                    thislen = estimatedMaxDataLen;\r\n\r\n                c.remoteWindow -= thislen;\r\n\r\n                msg = new byte[1 + 8 + thislen];\r\n\r\n                msg[0] = Packets.SSH_MSG_CHANNEL_DATA;\r\n                msg[1] = (byte) (c.remoteID >> 24);\r\n                msg[2] = (byte) (c.remoteID >> 16);\r\n                msg[3] = (byte) (c.remoteID >> 8);\r\n                msg[4] = (byte) (c.remoteID);\r\n                msg[5] = (byte) (thislen >> 24);\r\n                msg[6] = (byte) (thislen >> 16);\r\n                msg[7] = (byte) (thislen >> 8);\r\n                msg[8] = (byte) (thislen);\r\n\r\n                System.arraycopy(buffer, pos, msg, 9, thislen);\r\n            }\r\n\r\n            synchronized (c.channelSendLock) {\r\n                if (c.closeMessageSent == true)\r\n                    throw new IOException(\"SSH channel is closed. (\" + c.getReasonClosed() + \")\");\r\n\r\n                tm.sendMessage(msg);\r\n            }\r\n\r\n            pos += thislen;\r\n            len -= thislen;\r\n        }\r\n    }\r\n\r\n    public int requestGlobalForward(String bindAddress, int bindPort, String targetAddress, int targetPort)\r\n            throws IOException {\r\n        RemoteForwardingData rfd = new RemoteForwardingData();\r\n\r\n        rfd.bindAddress = bindAddress;\r\n        rfd.bindPort = bindPort;\r\n        rfd.targetAddress = targetAddress;\r\n        rfd.targetPort = targetPort;\r\n\r\n        synchronized (remoteForwardings) {\r\n            Integer key = new Integer(bindPort);\r\n\r\n            if (remoteForwardings.get(key) != null) {\r\n                throw new IOException(\"There is already a forwarding for remote port \" + bindPort);\r\n            }\r\n\r\n            remoteForwardings.put(key, rfd);\r\n        }\r\n\r\n        synchronized (channels) {\r\n            globalSuccessCounter = globalFailedCounter = 0;\r\n        }\r\n\r\n        PacketGlobalForwardRequest pgf = new PacketGlobalForwardRequest(true, bindAddress, bindPort);\r\n        tm.sendMessage(pgf.getPayload());\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Requesting a remote forwarding ('\" + bindAddress + \"', \" + bindPort + \")\");\r\n\r\n        try {\r\n            waitForGlobalSuccessOrFailure();\r\n        } catch (IOException e) {\r\n            synchronized (remoteForwardings) {\r\n                remoteForwardings.remove(rfd);\r\n            }\r\n            throw e;\r\n        }\r\n\r\n        return bindPort;\r\n    }\r\n\r\n    public void requestCancelGlobalForward(int bindPort) throws IOException {\r\n        RemoteForwardingData rfd = null;\r\n\r\n        synchronized (remoteForwardings) {\r\n            rfd = (RemoteForwardingData) remoteForwardings.get(new Integer(bindPort));\r\n\r\n            if (rfd == null)\r\n                throw new IOException(\"Sorry, there is no known remote forwarding for remote port \" + bindPort);\r\n        }\r\n\r\n        synchronized (channels) {\r\n            globalSuccessCounter = globalFailedCounter = 0;\r\n        }\r\n\r\n        PacketGlobalCancelForwardRequest pgcf = new PacketGlobalCancelForwardRequest(true, rfd.bindAddress,\r\n                rfd.bindPort);\r\n        tm.sendMessage(pgcf.getPayload());\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Requesting cancelation of remote forward ('\" + rfd.bindAddress + \"', \" + rfd.bindPort + \")\");\r\n\r\n        waitForGlobalSuccessOrFailure();\r\n\r\n\t\t/* Only now we are sure that no more forwarded connections will arrive */\r\n\r\n        synchronized (remoteForwardings) {\r\n            remoteForwardings.remove(rfd);\r\n        }\r\n    }\r\n\r\n    public void registerThread(IChannelWorkerThread thr) throws IOException {\r\n        synchronized (listenerThreads) {\r\n            if (listenerThreadsAllowed == false)\r\n                throw new IOException(\"Too late, this connection is closed.\");\r\n            listenerThreads.addElement(thr);\r\n        }\r\n    }\r\n\r\n    public Channel openDirectTCPIPChannel(String host_to_connect, int port_to_connect, String originator_IP_address,\r\n                                          int originator_port) throws IOException {\r\n        Channel c = new Channel(this);\r\n\r\n        synchronized (c) {\r\n            c.localID = addChannel(c);\r\n            // end of synchronized block forces writing out to main memory\r\n        }\r\n\r\n        PacketOpenDirectTCPIPChannel dtc = new PacketOpenDirectTCPIPChannel(c.localID, c.localWindow,\r\n                c.localMaxPacketSize, host_to_connect, port_to_connect, originator_IP_address, originator_port);\r\n\r\n        tm.sendMessage(dtc.getPayload());\r\n\r\n        waitUntilChannelOpen(c);\r\n\r\n        return c;\r\n    }\r\n\r\n    public Channel openSessionChannel() throws IOException {\r\n        Channel c = new Channel(this);\r\n\r\n        synchronized (c) {\r\n            c.localID = addChannel(c);\r\n            // end of synchronized block forces the writing out to main memory\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Sending SSH_MSG_CHANNEL_OPEN (Channel \" + c.localID + \")\");\r\n\r\n        PacketOpenSessionChannel smo = new PacketOpenSessionChannel(c.localID, c.localWindow, c.localMaxPacketSize);\r\n        tm.sendMessage(smo.getPayload());\r\n\r\n        waitUntilChannelOpen(c);\r\n\r\n        return c;\r\n    }\r\n\r\n    public void requestPTY(Channel c, String term, int term_width_characters, int term_height_characters,\r\n                           int term_width_pixels, int term_height_pixels, byte[] terminal_modes) throws IOException {\r\n        PacketSessionPtyRequest spr;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Cannot request PTY on this channel (\" + c.getReasonClosed() + \")\");\r\n\r\n            spr = new PacketSessionPtyRequest(c.remoteID, true, term, term_width_characters, term_height_characters,\r\n                    term_width_pixels, term_height_pixels, terminal_modes);\r\n\r\n            c.successCounter = c.failedCounter = 0;\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent)\r\n                throw new IOException(\"Cannot request PTY on this channel (\" + c.getReasonClosed() + \")\");\r\n            tm.sendMessage(spr.getPayload());\r\n        }\r\n\r\n        try {\r\n            waitForChannelSuccessOrFailure(c);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"PTY request failed\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void requestX11(Channel c, boolean singleConnection, String x11AuthenticationProtocol,\r\n                           String x11AuthenticationCookie, int x11ScreenNumber) throws IOException {\r\n        PacketSessionX11Request psr;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Cannot request X11 on this channel (\" + c.getReasonClosed() + \")\");\r\n\r\n            psr = new PacketSessionX11Request(c.remoteID, true, singleConnection, x11AuthenticationProtocol,\r\n                    x11AuthenticationCookie, x11ScreenNumber);\r\n\r\n            c.successCounter = c.failedCounter = 0;\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent)\r\n                throw new IOException(\"Cannot request X11 on this channel (\" + c.getReasonClosed() + \")\");\r\n            tm.sendMessage(psr.getPayload());\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Requesting X11 forwarding (Channel \" + c.localID + \"/\" + c.remoteID + \")\");\r\n\r\n        try {\r\n            waitForChannelSuccessOrFailure(c);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"The X11 request failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void requestSubSystem(Channel c, String subSystemName) throws IOException {\r\n        PacketSessionSubsystemRequest ssr;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Cannot request subsystem on this channel (\" + c.getReasonClosed() + \")\");\r\n\r\n            ssr = new PacketSessionSubsystemRequest(c.remoteID, true, subSystemName);\r\n\r\n            c.successCounter = c.failedCounter = 0;\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent)\r\n                throw new IOException(\"Cannot request subsystem on this channel (\" + c.getReasonClosed() + \")\");\r\n            tm.sendMessage(ssr.getPayload());\r\n        }\r\n\r\n        try {\r\n            waitForChannelSuccessOrFailure(c);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"The subsystem request failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void requestExecCommand(Channel c, String cmd) throws IOException {\r\n        PacketSessionExecCommand sm;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Cannot execute command on this channel (\" + c.getReasonClosed() + \")\");\r\n\r\n            sm = new PacketSessionExecCommand(c.remoteID, true, cmd);\r\n\r\n            c.successCounter = c.failedCounter = 0;\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent)\r\n                throw new IOException(\"Cannot execute command on this channel (\" + c.getReasonClosed() + \")\");\r\n            tm.sendMessage(sm.getPayload());\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Executing command (channel \" + c.localID + \", '\" + cmd + \"')\");\r\n\r\n        try {\r\n            waitForChannelSuccessOrFailure(c);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"The execute request failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void requestShell(Channel c) throws IOException {\r\n        PacketSessionStartShell sm;\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Cannot start shell on this channel (\" + c.getReasonClosed() + \")\");\r\n\r\n            sm = new PacketSessionStartShell(c.remoteID, true);\r\n\r\n            c.successCounter = c.failedCounter = 0;\r\n        }\r\n\r\n        synchronized (c.channelSendLock) {\r\n            if (c.closeMessageSent)\r\n                throw new IOException(\"Cannot start shell on this channel (\" + c.getReasonClosed() + \")\");\r\n            tm.sendMessage(sm.getPayload());\r\n        }\r\n\r\n        try {\r\n            waitForChannelSuccessOrFailure(c);\r\n        } catch (IOException e) {\r\n            throw (IOException) new IOException(\"The shell request failed.\").initCause(e);\r\n        }\r\n    }\r\n\r\n    public void msgChannelExtendedData(byte[] msg, int msglen) throws IOException {\r\n        if (msglen <= 13)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n        int dataType = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);\r\n        int len = ((msg[9] & 0xff) << 24) | ((msg[10] & 0xff) << 16) | ((msg[11] & 0xff) << 8) | (msg[12] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_EXTENDED_DATA message for non-existent channel \" + id);\r\n\r\n        if (dataType != Packets.SSH_EXTENDED_DATA_STDERR)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_EXTENDED_DATA message has unknown type (\" + dataType + \")\");\r\n\r\n        if (len != (msglen - 13))\r\n            throw new IOException(\"SSH_MSG_CHANNEL_EXTENDED_DATA message has wrong len (calculated \" + (msglen - 13)\r\n                    + \", got \" + len + \")\");\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_CHANNEL_EXTENDED_DATA (channel \" + id + \", \" + len + \")\");\r\n\r\n        synchronized (c) {\r\n            if (c.state == Channel.STATE_CLOSED)\r\n                return; // ignore\r\n\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Got SSH_MSG_CHANNEL_EXTENDED_DATA, but channel is not in correct state (\"\r\n                        + c.state + \")\");\r\n\r\n            if (c.localWindow < len)\r\n                throw new IOException(\"Remote sent too much data, does not fit into window.\");\r\n\r\n            c.localWindow -= len;\r\n\r\n            System.arraycopy(msg, 13, c.stderrBuffer, c.stderrWritepos, len);\r\n            c.stderrWritepos += len;\r\n\r\n            c.notifyAll();\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Wait until for a condition.\r\n     *\r\n     * @param c              Channel\r\n     * @param timeout        in ms, 0 means no timeout.\r\n     * @param condition_mask minimum event mask\r\n     * @return all current events\r\n     */\r\n    public int waitForCondition(Channel c, long timeout, int condition_mask) {\r\n        long end_time = 0;\r\n        boolean end_time_set = false;\r\n\r\n        synchronized (c) {\r\n            while (true) {\r\n                int current_cond = 0;\r\n\r\n                int stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;\r\n                int stderrAvail = c.stderrWritepos - c.stderrReadpos;\r\n\r\n                if (stdoutAvail > 0)\r\n                    current_cond = current_cond | ChannelCondition.STDOUT_DATA;\r\n\r\n                if (stderrAvail > 0)\r\n                    current_cond = current_cond | ChannelCondition.STDERR_DATA;\r\n\r\n                if (c.EOF)\r\n                    current_cond = current_cond | ChannelCondition.EOF;\r\n\r\n                if (c.getExitStatus() != null)\r\n                    current_cond = current_cond | ChannelCondition.EXIT_STATUS;\r\n\r\n                if (c.getExitSignal() != null)\r\n                    current_cond = current_cond | ChannelCondition.EXIT_SIGNAL;\r\n\r\n                if (c.state == Channel.STATE_CLOSED)\r\n                    return current_cond | ChannelCondition.CLOSED | ChannelCondition.EOF;\r\n\r\n                if ((current_cond & condition_mask) != 0)\r\n                    return current_cond;\r\n\r\n                if (timeout > 0) {\r\n                    if (!end_time_set) {\r\n                        end_time = System.currentTimeMillis() + timeout;\r\n                        end_time_set = true;\r\n                    } else {\r\n                        timeout = end_time - System.currentTimeMillis();\r\n\r\n                        if (timeout <= 0)\r\n                            return current_cond | ChannelCondition.TIMEOUT;\r\n                    }\r\n                }\r\n\r\n                try {\r\n                    if (timeout > 0)\r\n                        c.wait(timeout);\r\n                    else\r\n                        c.wait();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    public int getAvailable(Channel c, boolean extended) throws IOException {\r\n        synchronized (c) {\r\n            int avail;\r\n\r\n            if (extended)\r\n                avail = c.stderrWritepos - c.stderrReadpos;\r\n            else\r\n                avail = c.stdoutWritepos - c.stdoutReadpos;\r\n\r\n            return ((avail > 0) ? avail : (c.EOF ? -1 : 0));\r\n        }\r\n    }\r\n\r\n    public int getChannelData(Channel c, boolean extended, byte[] target, int off, int len) throws IOException {\r\n        int copylen = 0;\r\n        int increment = 0;\r\n        int remoteID = 0;\r\n        int localID = 0;\r\n\r\n        synchronized (c) {\r\n            int stdoutAvail = 0;\r\n            int stderrAvail = 0;\r\n\r\n            while (true) {\r\n                /*\r\n\t\t\t\t * Data available? We have to return remaining data even if the\r\n\t\t\t\t * channel is already closed.\r\n\t\t\t\t */\r\n\r\n                stdoutAvail = c.stdoutWritepos - c.stdoutReadpos;\r\n                stderrAvail = c.stderrWritepos - c.stderrReadpos;\r\n\r\n                if ((!extended) && (stdoutAvail != 0))\r\n                    break;\r\n\r\n                if ((extended) && (stderrAvail != 0))\r\n                    break;\r\n\r\n\t\t\t\t/* Do not wait if more data will never arrive (EOF or CLOSED) */\r\n\r\n                if ((c.EOF) || (c.state != Channel.STATE_OPEN))\r\n                    return -1;\r\n\r\n                try {\r\n                    c.wait();\r\n                } catch (InterruptedException ignore) {\r\n                }\r\n            }\r\n\r\n\t\t\t/* OK, there is some data. Return it. */\r\n\r\n            if (!extended) {\r\n                copylen = (stdoutAvail > len) ? len : stdoutAvail;\r\n                System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, target, off, copylen);\r\n                c.stdoutReadpos += copylen;\r\n\r\n                if (c.stdoutReadpos != c.stdoutWritepos)\r\n\r\n                    System.arraycopy(c.stdoutBuffer, c.stdoutReadpos, c.stdoutBuffer, 0, c.stdoutWritepos\r\n                            - c.stdoutReadpos);\r\n\r\n                c.stdoutWritepos -= c.stdoutReadpos;\r\n                c.stdoutReadpos = 0;\r\n            } else {\r\n                copylen = (stderrAvail > len) ? len : stderrAvail;\r\n                System.arraycopy(c.stderrBuffer, c.stderrReadpos, target, off, copylen);\r\n                c.stderrReadpos += copylen;\r\n\r\n                if (c.stderrReadpos != c.stderrWritepos)\r\n\r\n                    System.arraycopy(c.stderrBuffer, c.stderrReadpos, c.stderrBuffer, 0, c.stderrWritepos\r\n                            - c.stderrReadpos);\r\n\r\n                c.stderrWritepos -= c.stderrReadpos;\r\n                c.stderrReadpos = 0;\r\n            }\r\n\r\n            if (c.state != Channel.STATE_OPEN)\r\n                return copylen;\r\n\r\n            if (c.localWindow < ((Channel.CHANNEL_BUFFER_SIZE + 1) / 2)) {\r\n                int minFreeSpace = Math.min(Channel.CHANNEL_BUFFER_SIZE - c.stdoutWritepos, Channel.CHANNEL_BUFFER_SIZE\r\n                        - c.stderrWritepos);\r\n\r\n                increment = minFreeSpace - c.localWindow;\r\n                c.localWindow = minFreeSpace;\r\n            }\r\n\r\n            remoteID = c.remoteID; /* read while holding the lock */\r\n            localID = c.localID; /* read while holding the lock */\r\n        }\r\n\r\n\t\t/*\r\n\t\t * If a consumer reads stdout and stdin in parallel, we may end up with\r\n\t\t * sending two msgWindowAdjust messages. Luckily, it\r\n\t\t * does not matter in which order they arrive at the server.\r\n\t\t */\r\n\r\n        if (increment > 0) {\r\n            if (log.isEnabled())\r\n                log.log(80, \"Sending SSH_MSG_CHANNEL_WINDOW_ADJUST (channel \" + localID + \", \" + increment + \")\");\r\n\r\n            synchronized (c.channelSendLock) {\r\n                byte[] msg = c.msgWindowAdjust;\r\n\r\n                msg[0] = Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST;\r\n                msg[1] = (byte) (remoteID >> 24);\r\n                msg[2] = (byte) (remoteID >> 16);\r\n                msg[3] = (byte) (remoteID >> 8);\r\n                msg[4] = (byte) (remoteID);\r\n                msg[5] = (byte) (increment >> 24);\r\n                msg[6] = (byte) (increment >> 16);\r\n                msg[7] = (byte) (increment >> 8);\r\n                msg[8] = (byte) (increment);\r\n\r\n                if (c.closeMessageSent == false)\r\n                    tm.sendMessage(msg);\r\n            }\r\n        }\r\n\r\n        return copylen;\r\n    }\r\n\r\n    public void msgChannelData(byte[] msg, int msglen) throws IOException {\r\n        if (msglen <= 9)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_DATA message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n        int len = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_DATA message for non-existent channel \" + id);\r\n\r\n        if (len != (msglen - 9))\r\n            throw new IOException(\"SSH_MSG_CHANNEL_DATA message has wrong len (calculated \" + (msglen - 9) + \", got \"\r\n                    + len + \")\");\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_CHANNEL_DATA (channel \" + id + \", \" + len + \")\");\r\n\r\n        synchronized (c) {\r\n            if (c.state == Channel.STATE_CLOSED)\r\n                return; // ignore\r\n\r\n            if (c.state != Channel.STATE_OPEN)\r\n                throw new IOException(\"Got SSH_MSG_CHANNEL_DATA, but channel is not in correct state (\" + c.state + \")\");\r\n\r\n            if (c.localWindow < len)\r\n                throw new IOException(\"Remote sent too much data, does not fit into window.\");\r\n\r\n            c.localWindow -= len;\r\n\r\n            System.arraycopy(msg, 9, c.stdoutBuffer, c.stdoutWritepos, len);\r\n            c.stdoutWritepos += len;\r\n\r\n            c.notifyAll();\r\n        }\r\n    }\r\n\r\n    public void msgChannelWindowAdjust(byte[] msg, int msglen) throws IOException {\r\n        if (msglen != 9)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_WINDOW_ADJUST message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n        int windowChange = ((msg[5] & 0xff) << 24) | ((msg[6] & 0xff) << 16) | ((msg[7] & 0xff) << 8) | (msg[8] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_WINDOW_ADJUST message for non-existent channel \" + id);\r\n\r\n        synchronized (c) {\r\n            final long huge = 0xFFFFffffL; /* 2^32 - 1 */\r\n\r\n            c.remoteWindow += (windowChange & huge); /* avoid sign extension */\r\n\r\n\t\t\t/* TODO - is this a good heuristic? */\r\n\r\n            if ((c.remoteWindow > huge))\r\n                c.remoteWindow = huge;\r\n\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_CHANNEL_WINDOW_ADJUST (channel \" + id + \", \" + windowChange + \")\");\r\n    }\r\n\r\n    public void msgChannelOpen(byte[] msg, int msglen) throws IOException {\r\n        TypesReader tr = new TypesReader(msg, 0, msglen);\r\n\r\n        tr.readByte(); // skip packet type\r\n        String channelType = tr.readString();\r\n        int remoteID = tr.readUINT32(); /* sender channel */\r\n        int remoteWindow = tr.readUINT32(); /* initial window size */\r\n        int remoteMaxPacketSize = tr.readUINT32(); /* maximum packet size */\r\n\r\n        if (\"x11\".equals(channelType)) {\r\n            synchronized (x11_magic_cookies) {\r\n\t\t\t\t/* If we did not request X11 forwarding, then simply ignore this bogus request. */\r\n\r\n                if (x11_magic_cookies.size() == 0) {\r\n                    PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,\r\n                            Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED, \"X11 forwarding not activated\", \"\");\r\n\r\n                    tm.sendAsynchronousMessage(pcof.getPayload());\r\n\r\n                    if (log.isEnabled())\r\n                        log.log(20, \"Unexpected X11 request, denying it!\");\r\n\r\n                    return;\r\n                }\r\n            }\r\n\r\n            String remoteOriginatorAddress = tr.readString();\r\n            int remoteOriginatorPort = tr.readUINT32();\r\n\r\n            Channel c = new Channel(this);\r\n\r\n            synchronized (c) {\r\n                c.remoteID = remoteID;\r\n                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* properly convert UINT32 to long */\r\n                c.remoteMaxPacketSize = remoteMaxPacketSize;\r\n                c.localID = addChannel(c);\r\n            }\r\n\r\n\t\t\t/*\r\n\t\t\t * The open confirmation message will be sent from another thread\r\n\t\t\t */\r\n\r\n            RemoteX11AcceptThread rxat = new RemoteX11AcceptThread(c, remoteOriginatorAddress, remoteOriginatorPort);\r\n            rxat.setDaemon(true);\r\n            rxat.start();\r\n\r\n            return;\r\n        }\r\n\r\n        if (\"forwarded-tcpip\".equals(channelType)) {\r\n            String remoteConnectedAddress = tr.readString(); /* address that was connected */\r\n            int remoteConnectedPort = tr.readUINT32(); /* port that was connected */\r\n            String remoteOriginatorAddress = tr.readString(); /* originator IP address */\r\n            int remoteOriginatorPort = tr.readUINT32(); /* originator port */\r\n\r\n            RemoteForwardingData rfd = null;\r\n\r\n            synchronized (remoteForwardings) {\r\n                rfd = (RemoteForwardingData) remoteForwardings.get(new Integer(remoteConnectedPort));\r\n            }\r\n\r\n            if (rfd == null) {\r\n                PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID,\r\n                        Packets.SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,\r\n                        \"No thanks, unknown port in forwarded-tcpip request\", \"\");\r\n\r\n\t\t\t\t/* Always try to be polite. */\r\n\r\n                tm.sendAsynchronousMessage(pcof.getPayload());\r\n\r\n                if (log.isEnabled())\r\n                    log.log(20, \"Unexpected forwarded-tcpip request, denying it!\");\r\n\r\n                return;\r\n            }\r\n\r\n            Channel c = new Channel(this);\r\n\r\n            synchronized (c) {\r\n                c.remoteID = remoteID;\r\n                c.remoteWindow = remoteWindow & 0xFFFFffffL; /* convert UINT32 to long */\r\n                c.remoteMaxPacketSize = remoteMaxPacketSize;\r\n                c.localID = addChannel(c);\r\n            }\r\n\r\n\t\t\t/*\r\n\t\t\t * The open confirmation message will be sent from another thread.\r\n\t\t\t */\r\n\r\n            RemoteAcceptThread rat = new RemoteAcceptThread(c, remoteConnectedAddress, remoteConnectedPort,\r\n                    remoteOriginatorAddress, remoteOriginatorPort, rfd.targetAddress, rfd.targetPort);\r\n\r\n            rat.setDaemon(true);\r\n            rat.start();\r\n\r\n            return;\r\n        }\r\n\r\n\t\t/* Tell the server that we have no idea what it is talking about */\r\n\r\n        PacketChannelOpenFailure pcof = new PacketChannelOpenFailure(remoteID, Packets.SSH_OPEN_UNKNOWN_CHANNEL_TYPE,\r\n                \"Unknown channel type\", \"\");\r\n\r\n        tm.sendAsynchronousMessage(pcof.getPayload());\r\n\r\n        if (log.isEnabled())\r\n            log.log(20, \"The peer tried to open an unsupported channel type (\" + channelType + \")\");\r\n    }\r\n\r\n    public void msgChannelRequest(byte[] msg, int msglen) throws IOException {\r\n        TypesReader tr = new TypesReader(msg, 0, msglen);\r\n\r\n        tr.readByte(); // skip packet type\r\n        int id = tr.readUINT32();\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_REQUEST message for non-existent channel \" + id);\r\n\r\n        String type = tr.readString(\"US-ASCII\");\r\n        boolean wantReply = tr.readBoolean();\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_CHANNEL_REQUEST (channel \" + id + \", '\" + type + \"')\");\r\n\r\n        if (type.equals(\"exit-status\")) {\r\n            if (wantReply != false)\r\n                throw new IOException(\"Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true\");\r\n\r\n            int exit_status = tr.readUINT32();\r\n\r\n            if (tr.remain() != 0)\r\n                throw new IOException(\"Badly formatted SSH_MSG_CHANNEL_REQUEST message\");\r\n\r\n            synchronized (c) {\r\n                c.exit_status = new Integer(exit_status);\r\n                c.notifyAll();\r\n            }\r\n\r\n            if (log.isEnabled())\r\n                log.log(50, \"Got EXIT STATUS (channel \" + id + \", status \" + exit_status + \")\");\r\n\r\n            return;\r\n        }\r\n\r\n        if (type.equals(\"exit-signal\")) {\r\n            if (wantReply != false)\r\n                throw new IOException(\"Badly formatted SSH_MSG_CHANNEL_REQUEST message, 'want reply' is true\");\r\n\r\n            String signame = tr.readString(\"US-ASCII\");\r\n            tr.readBoolean();\r\n            tr.readString();\r\n            tr.readString();\r\n\r\n            if (tr.remain() != 0)\r\n                throw new IOException(\"Badly formatted SSH_MSG_CHANNEL_REQUEST message\");\r\n\r\n            synchronized (c) {\r\n                c.exit_signal = signame;\r\n                c.notifyAll();\r\n            }\r\n\r\n            if (log.isEnabled())\r\n                log.log(50, \"Got EXIT SIGNAL (channel \" + id + \", signal \" + signame + \")\");\r\n\r\n            return;\r\n        }\r\n\r\n\t\t/* We simply ignore unknown channel requests, however, if the server wants a reply,\r\n\t\t * then we signal that we have no idea what it is about.\r\n\t\t */\r\n\r\n        if (wantReply) {\r\n            byte[] reply = new byte[5];\r\n\r\n            reply[0] = Packets.SSH_MSG_CHANNEL_FAILURE;\r\n            reply[1] = (byte) (c.remoteID >> 24);\r\n            reply[2] = (byte) (c.remoteID >> 16);\r\n            reply[3] = (byte) (c.remoteID >> 8);\r\n            reply[4] = (byte) (c.remoteID);\r\n\r\n            tm.sendAsynchronousMessage(reply);\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Channel request '\" + type + \"' is not known, ignoring it\");\r\n    }\r\n\r\n    public void msgChannelEOF(byte[] msg, int msglen) throws IOException {\r\n        if (msglen != 5)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_EOF message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_EOF message for non-existent channel \" + id);\r\n\r\n        synchronized (c) {\r\n            c.EOF = true;\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Got SSH_MSG_CHANNEL_EOF (channel \" + id + \")\");\r\n    }\r\n\r\n    public void msgChannelClose(byte[] msg, int msglen) throws IOException {\r\n        if (msglen != 5)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_CLOSE message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_CLOSE message for non-existent channel \" + id);\r\n\r\n        synchronized (c) {\r\n            c.EOF = true;\r\n            c.state = Channel.STATE_CLOSED;\r\n            c.setReasonClosed(\"Close requested by remote\");\r\n            c.closeMessageRecv = true;\r\n\r\n            removeChannel(c.localID);\r\n\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Got SSH_MSG_CHANNEL_CLOSE (channel \" + id + \")\");\r\n    }\r\n\r\n    public void msgChannelSuccess(byte[] msg, int msglen) throws IOException {\r\n        if (msglen != 5)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_SUCCESS message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_SUCCESS message for non-existent channel \" + id);\r\n\r\n        synchronized (c) {\r\n            c.successCounter++;\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_CHANNEL_SUCCESS (channel \" + id + \")\");\r\n    }\r\n\r\n    public void msgChannelFailure(byte[] msg, int msglen) throws IOException {\r\n        if (msglen != 5)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_FAILURE message has wrong size (\" + msglen + \")\");\r\n\r\n        int id = ((msg[1] & 0xff) << 24) | ((msg[2] & 0xff) << 16) | ((msg[3] & 0xff) << 8) | (msg[4] & 0xff);\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_FAILURE message for non-existent channel \" + id);\r\n\r\n        synchronized (c) {\r\n            c.failedCounter++;\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Got SSH_MSG_CHANNEL_FAILURE (channel \" + id + \")\");\r\n    }\r\n\r\n    public void msgChannelOpenConfirmation(byte[] msg, int msglen) throws IOException {\r\n        PacketChannelOpenConfirmation sm = new PacketChannelOpenConfirmation(msg, 0, msglen);\r\n\r\n        Channel c = getChannel(sm.recipientChannelID);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for non-existent channel \"\r\n                    + sm.recipientChannelID);\r\n\r\n        synchronized (c) {\r\n            if (c.state != Channel.STATE_OPENING)\r\n                throw new IOException(\"Unexpected SSH_MSG_CHANNEL_OPEN_CONFIRMATION message for channel \"\r\n                        + sm.recipientChannelID);\r\n\r\n            c.remoteID = sm.senderChannelID;\r\n            c.remoteWindow = sm.initialWindowSize & 0xFFFFffffL; /* convert UINT32 to long */\r\n            c.remoteMaxPacketSize = sm.maxPacketSize;\r\n            c.state = Channel.STATE_OPEN;\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Got SSH_MSG_CHANNEL_OPEN_CONFIRMATION (channel \" + sm.recipientChannelID + \" / remote: \"\r\n                    + sm.senderChannelID + \")\");\r\n    }\r\n\r\n    public void msgChannelOpenFailure(byte[] msg, int msglen) throws IOException {\r\n        if (msglen < 5)\r\n            throw new IOException(\"SSH_MSG_CHANNEL_OPEN_FAILURE message has wrong size (\" + msglen + \")\");\r\n\r\n        TypesReader tr = new TypesReader(msg, 0, msglen);\r\n\r\n        tr.readByte(); // skip packet type\r\n        int id = tr.readUINT32(); /* sender channel */\r\n\r\n        Channel c = getChannel(id);\r\n\r\n        if (c == null)\r\n            throw new IOException(\"Unexpected SSH_MSG_CHANNEL_OPEN_FAILURE message for non-existent channel \" + id);\r\n\r\n        int reasonCode = tr.readUINT32();\r\n        String description = tr.readString(\"UTF-8\");\r\n\r\n        String reasonCodeSymbolicName = null;\r\n\r\n        switch (reasonCode) {\r\n            case 1:\r\n                reasonCodeSymbolicName = \"SSH_OPEN_ADMINISTRATIVELY_PROHIBITED\";\r\n                break;\r\n            case 2:\r\n                reasonCodeSymbolicName = \"SSH_OPEN_CONNECT_FAILED\";\r\n                break;\r\n            case 3:\r\n                reasonCodeSymbolicName = \"SSH_OPEN_UNKNOWN_CHANNEL_TYPE\";\r\n                break;\r\n            case 4:\r\n                reasonCodeSymbolicName = \"SSH_OPEN_RESOURCE_SHORTAGE\";\r\n                break;\r\n            default:\r\n                reasonCodeSymbolicName = \"UNKNOWN REASON CODE (\" + reasonCode + \")\";\r\n        }\r\n\r\n        StringBuffer descriptionBuffer = new StringBuffer();\r\n        descriptionBuffer.append(description);\r\n\r\n        for (int i = 0; i < descriptionBuffer.length(); i++) {\r\n            char cc = descriptionBuffer.charAt(i);\r\n\r\n            if ((cc >= 32) && (cc <= 126))\r\n                continue;\r\n            descriptionBuffer.setCharAt(i, '\\uFFFD');\r\n        }\r\n\r\n        synchronized (c) {\r\n            c.EOF = true;\r\n            c.state = Channel.STATE_CLOSED;\r\n            c.setReasonClosed(\"The server refused to open the channel (\" + reasonCodeSymbolicName + \", '\"\r\n                    + descriptionBuffer.toString() + \"')\");\r\n            c.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(50, \"Got SSH_MSG_CHANNEL_OPEN_FAILURE (channel \" + id + \")\");\r\n    }\r\n\r\n    public void msgGlobalRequest(byte[] msg, int msglen) throws IOException {\r\n\t\t/* Currently we do not support any kind of global request */\r\n\r\n        TypesReader tr = new TypesReader(msg, 0, msglen);\r\n\r\n        tr.readByte(); // skip packet type\r\n        String requestName = tr.readString();\r\n        boolean wantReply = tr.readBoolean();\r\n\r\n        if (wantReply) {\r\n            byte[] reply_failure = new byte[1];\r\n            reply_failure[0] = Packets.SSH_MSG_REQUEST_FAILURE;\r\n\r\n            tm.sendAsynchronousMessage(reply_failure);\r\n        }\r\n\r\n\t\t/* We do not clean up the requestName String - that is OK for debug */\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_GLOBAL_REQUEST (\" + requestName + \")\");\r\n    }\r\n\r\n    public void msgGlobalSuccess() throws IOException {\r\n        synchronized (channels) {\r\n            globalSuccessCounter++;\r\n            channels.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_REQUEST_SUCCESS\");\r\n    }\r\n\r\n    public void msgGlobalFailure() throws IOException {\r\n        synchronized (channels) {\r\n            globalFailedCounter++;\r\n            channels.notifyAll();\r\n        }\r\n\r\n        if (log.isEnabled())\r\n            log.log(80, \"Got SSH_MSG_REQUEST_FAILURE\");\r\n    }\r\n\r\n    public void handleMessage(byte[] msg, int msglen) throws IOException {\r\n        if (msg == null) {\r\n            if (log.isEnabled())\r\n                log.log(50, \"HandleMessage: got shutdown\");\r\n\r\n            synchronized (listenerThreads) {\r\n                for (int i = 0; i < listenerThreads.size(); i++) {\r\n                    IChannelWorkerThread lat = (IChannelWorkerThread) listenerThreads.elementAt(i);\r\n                    lat.stopWorking();\r\n                }\r\n                listenerThreadsAllowed = false;\r\n            }\r\n\r\n            synchronized (channels) {\r\n                shutdown = true;\r\n\r\n                for (int i = 0; i < channels.size(); i++) {\r\n                    Channel c = (Channel) channels.elementAt(i);\r\n                    synchronized (c) {\r\n                        c.EOF = true;\r\n                        c.state = Channel.STATE_CLOSED;\r\n                        c.setReasonClosed(\"The connection is being shutdown\");\r\n                        c.closeMessageRecv = true; /*\r\n\t\t\t\t\t\t * You never know, perhaps\r\n\t\t\t\t\t\t * we are waiting for a\r\n\t\t\t\t\t\t * pending close message\r\n\t\t\t\t\t\t * from the server...\r\n\t\t\t\t\t\t */\r\n                        c.notifyAll();\r\n                    }\r\n                }\r\n\t\t\t\t/* Works with J2ME */\r\n                channels.setSize(0);\r\n                channels.trimToSize();\r\n                channels.notifyAll(); /* Notify global response waiters */\r\n                return;\r\n            }\r\n        }\r\n\r\n        switch (msg[0]) {\r\n            case Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:\r\n                msgChannelOpenConfirmation(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST:\r\n                msgChannelWindowAdjust(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_DATA:\r\n                msgChannelData(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_EXTENDED_DATA:\r\n                msgChannelExtendedData(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_REQUEST:\r\n                msgChannelRequest(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_EOF:\r\n                msgChannelEOF(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_OPEN:\r\n                msgChannelOpen(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_CLOSE:\r\n                msgChannelClose(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_SUCCESS:\r\n                msgChannelSuccess(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_FAILURE:\r\n                msgChannelFailure(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_CHANNEL_OPEN_FAILURE:\r\n                msgChannelOpenFailure(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_GLOBAL_REQUEST:\r\n                msgGlobalRequest(msg, msglen);\r\n                break;\r\n            case Packets.SSH_MSG_REQUEST_SUCCESS:\r\n                msgGlobalSuccess();\r\n                break;\r\n            case Packets.SSH_MSG_REQUEST_FAILURE:\r\n                msgGlobalFailure();\r\n                break;\r\n            default:\r\n                throw new IOException(\"Cannot handle unknown channel message \" + (msg[0] & 0xff));\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/ChannelOutputStream.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\n\r\n/**\r\n * ChannelOutputStream.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ChannelOutputStream.java,v 1.3 2005/08/11 12:47:30 cplattne Exp $\r\n */\r\npublic final class ChannelOutputStream extends OutputStream {\r\n    Channel c;\r\n\r\n    boolean isClosed = false;\r\n\r\n    ChannelOutputStream(Channel c) {\r\n        this.c = c;\r\n    }\r\n\r\n    public void write(int b) throws IOException {\r\n        byte[] buff = new byte[1];\r\n\r\n        buff[0] = (byte) b;\r\n\r\n        write(buff, 0, 1);\r\n    }\r\n\r\n    public void close() throws IOException {\r\n        if (isClosed == false) {\r\n            isClosed = true;\r\n            c.cm.sendEOF(c);\r\n        }\r\n    }\r\n\r\n    public void flush() throws IOException {\r\n        if (isClosed)\r\n            throw new IOException(\"This OutputStream is closed.\");\r\n\r\n\t\t/* This is a no-op, since this stream is unbuffered */\r\n    }\r\n\r\n    public void write(byte[] b, int off, int len) throws IOException {\r\n        if (isClosed)\r\n            throw new IOException(\"This OutputStream is closed.\");\r\n\r\n        if (b == null)\r\n            throw new NullPointerException();\r\n\r\n        if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length))\r\n            throw new IndexOutOfBoundsException();\r\n\r\n        if (len == 0)\r\n            return;\r\n\r\n        c.cm.sendData(c, b, off, len);\r\n    }\r\n\r\n    public void write(byte[] b) throws IOException {\r\n        write(b, 0, b.length);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/IChannelWorkerThread.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\n/**\r\n * IChannelWorkerThread.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: IChannelWorkerThread.java,v 1.2 2005/12/05 17:13:26 cplattne Exp $\r\n */\r\ninterface IChannelWorkerThread {\r\n    public void stopWorking();\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/LocalAcceptThread.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport java.io.IOException;\r\nimport java.net.ServerSocket;\r\nimport java.net.Socket;\r\n\r\n/**\r\n * LocalAcceptThread.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: LocalAcceptThread.java,v 1.7 2006/07/30 21:59:29 cplattne Exp $\r\n */\r\npublic class LocalAcceptThread extends Thread implements IChannelWorkerThread {\r\n    final ServerSocket ss;\r\n    ChannelManager cm;\r\n    int local_port;\r\n    String host_to_connect;\r\n    int port_to_connect;\r\n\r\n    public LocalAcceptThread(ChannelManager cm, int local_port, String host_to_connect, int port_to_connect)\r\n            throws IOException {\r\n        this.cm = cm;\r\n        this.local_port = local_port;\r\n        this.host_to_connect = host_to_connect;\r\n        this.port_to_connect = port_to_connect;\r\n\r\n        ss = new ServerSocket(local_port);\r\n    }\r\n\r\n    public void run() {\r\n        try {\r\n            cm.registerThread(this);\r\n        } catch (IOException e) {\r\n            stopWorking();\r\n            return;\r\n        }\r\n\r\n        while (true) {\r\n            Socket s = null;\r\n\r\n            try {\r\n                s = ss.accept();\r\n            } catch (IOException e) {\r\n                stopWorking();\r\n                return;\r\n            }\r\n\r\n            Channel cn = null;\r\n            StreamForwarder r2l = null;\r\n            StreamForwarder l2r = null;\r\n\r\n            try {\r\n                /* This may fail, e.g., if the remote port is closed (in optimistic terms: not open yet) */\r\n\r\n                cn = cm.openDirectTCPIPChannel(host_to_connect, port_to_connect, s.getInetAddress().getHostAddress(), s\r\n                        .getPort());\r\n\r\n            } catch (IOException e) {\r\n\t\t\t\t/* Simply close the local socket and wait for the next incoming connection */\r\n\r\n                try {\r\n                    s.close();\r\n                } catch (IOException ignore) {\r\n                }\r\n\r\n                continue;\r\n            }\r\n\r\n            try {\r\n                r2l = new StreamForwarder(cn, null, null, cn.stdoutStream, s.getOutputStream(), \"RemoteToLocal\");\r\n                l2r = new StreamForwarder(cn, r2l, s, s.getInputStream(), cn.stdinStream, \"LocalToRemote\");\r\n            } catch (IOException e) {\r\n                try {\r\n\t\t\t\t\t/* This message is only visible during debugging, since we discard the channel immediatelly */\r\n                    cn.cm.closeChannel(cn, \"Weird error during creation of StreamForwarder (\" + e.getMessage() + \")\",\r\n                            true);\r\n                } catch (IOException ignore) {\r\n                }\r\n\r\n                continue;\r\n            }\r\n\r\n            r2l.setDaemon(true);\r\n            l2r.setDaemon(true);\r\n            r2l.start();\r\n            l2r.start();\r\n        }\r\n    }\r\n\r\n    public void stopWorking() {\r\n        try {\r\n\t\t\t/* This will lead to an IOException in the ss.accept() call */\r\n            ss.close();\r\n        } catch (IOException e) {\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/RemoteAcceptThread.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport ch.ethz.ssh2.log.Logger;\r\n\r\nimport java.io.IOException;\r\nimport java.net.Socket;\r\n\r\n/**\r\n * RemoteAcceptThread.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RemoteAcceptThread.java,v 1.4 2006/02/13 21:19:25 cplattne Exp $\r\n */\r\npublic class RemoteAcceptThread extends Thread {\r\n    private static final Logger log = Logger.getLogger(RemoteAcceptThread.class);\r\n\r\n    Channel c;\r\n\r\n    String remoteConnectedAddress;\r\n    int remoteConnectedPort;\r\n    String remoteOriginatorAddress;\r\n    int remoteOriginatorPort;\r\n    String targetAddress;\r\n    int targetPort;\r\n\r\n    Socket s;\r\n\r\n    public RemoteAcceptThread(Channel c, String remoteConnectedAddress, int remoteConnectedPort,\r\n                              String remoteOriginatorAddress, int remoteOriginatorPort, String targetAddress, int targetPort) {\r\n        this.c = c;\r\n        this.remoteConnectedAddress = remoteConnectedAddress;\r\n        this.remoteConnectedPort = remoteConnectedPort;\r\n        this.remoteOriginatorAddress = remoteOriginatorAddress;\r\n        this.remoteOriginatorPort = remoteOriginatorPort;\r\n        this.targetAddress = targetAddress;\r\n        this.targetPort = targetPort;\r\n\r\n        if (log.isEnabled())\r\n            log.log(20, \"RemoteAcceptThread: \" + remoteConnectedAddress + \"/\" + remoteConnectedPort + \", R: \"\r\n                    + remoteOriginatorAddress + \"/\" + remoteOriginatorPort);\r\n    }\r\n\r\n    public void run() {\r\n        try {\r\n            c.cm.sendOpenConfirmation(c);\r\n\r\n            s = new Socket(targetAddress, targetPort);\r\n\r\n            StreamForwarder r2l = new StreamForwarder(c, null, null, c.getStdoutStream(), s.getOutputStream(),\r\n                    \"RemoteToLocal\");\r\n            StreamForwarder l2r = new StreamForwarder(c, null, null, s.getInputStream(), c.getStdinStream(),\r\n                    \"LocalToRemote\");\r\n\r\n\t\t\t/* No need to start two threads, one can be executed in the current thread */\r\n\r\n            r2l.setDaemon(true);\r\n            r2l.start();\r\n            l2r.run();\r\n\r\n            while (r2l.isAlive()) {\r\n                try {\r\n                    r2l.join();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n\r\n\t\t\t/* If the channel is already closed, then this is a no-op */\r\n\r\n            c.cm.closeChannel(c, \"EOF on both streams reached.\", true);\r\n            s.close();\r\n        } catch (IOException e) {\r\n            log.log(50, \"IOException in proxy code: \" + e.getMessage());\r\n\r\n            try {\r\n                c.cm.closeChannel(c, \"IOException in proxy code (\" + e.getMessage() + \")\", true);\r\n            } catch (IOException e1) {\r\n            }\r\n            try {\r\n                if (s != null)\r\n                    s.close();\r\n            } catch (IOException e1) {\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/RemoteForwardingData.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\n/**\r\n * RemoteForwardingData. Data about a requested remote forwarding.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RemoteForwardingData.java,v 1.1 2005/12/07 10:25:48 cplattne Exp $\r\n */\r\npublic class RemoteForwardingData {\r\n    public String bindAddress;\r\n    public int bindPort;\r\n\r\n    String targetAddress;\r\n    int targetPort;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/RemoteX11AcceptThread.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport ch.ethz.ssh2.log.Logger;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.net.Socket;\r\n\r\n/**\r\n * RemoteX11AcceptThread.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RemoteX11AcceptThread.java,v 1.5 2006/02/14 15:17:37 cplattne Exp $\r\n */\r\npublic class RemoteX11AcceptThread extends Thread {\r\n    private static final Logger log = Logger.getLogger(RemoteX11AcceptThread.class);\r\n\r\n    Channel c;\r\n\r\n    String remoteOriginatorAddress;\r\n    int remoteOriginatorPort;\r\n\r\n    Socket s;\r\n\r\n    public RemoteX11AcceptThread(Channel c, String remoteOriginatorAddress, int remoteOriginatorPort) {\r\n        this.c = c;\r\n        this.remoteOriginatorAddress = remoteOriginatorAddress;\r\n        this.remoteOriginatorPort = remoteOriginatorPort;\r\n    }\r\n\r\n    public void run() {\r\n        try {\r\n            /* Send Open Confirmation */\r\n\r\n            c.cm.sendOpenConfirmation(c);\r\n\r\n\t\t\t/* Read startup packet from client */\r\n\r\n            OutputStream remote_os = c.getStdinStream();\r\n            InputStream remote_is = c.getStdoutStream();\r\n\r\n\t\t\t/* The following code is based on the protocol description given in:\r\n\t\t\t * Scheifler/Gettys,\r\n\t\t\t * X Windows System: Core and Extension Protocols:\r\n\t\t\t * X Version 11, Releases 6 and 6.1 ISBN 1-55558-148-X\r\n\t\t\t * (from the ETH library - after being here for almost ten\r\n\t\t\t * years one of the few books I borrowed... sad but true =)\r\n\t\t\t */\r\n\r\n\t\t\t/*\r\n\t\t\t * Client startup:\r\n\t\t\t * \r\n\t\t\t * 1 0X42 MSB first/0x6c lSB first - byteorder\r\n\t\t\t * 1 - unused\r\n\t\t\t * 2 card16 - protocol-major-version\r\n\t\t\t * 2 card16 - protocol-minor-version\r\n\t\t\t * 2 n - lenght of authorization-protocol-name\r\n\t\t\t * 2 d - lenght of authorization-protocol-data\r\n\t\t\t * 2 - unused\r\n\t\t\t * string8 - authorization-protocol-name\r\n\t\t\t * p - unused, p=pad(n)\r\n\t\t\t * string8 - authorization-protocol-data\r\n\t\t\t * q - unused, q=pad(d)\r\n\t\t\t * \r\n\t\t\t * pad(X) = (4 - (X mod 4)) mod 4\r\n\t\t\t * \r\n\t\t\t * Server response:\r\n\t\t\t * \r\n\t\t\t * 1 (0 failed, 2 authenticate, 1 success)\r\n\t\t\t * ...\r\n\t\t\t * \r\n\t\t\t */\r\n\r\n\t\t\t/* Later on we will simply forward the first 6 header bytes to the \"real\" X11 server */\r\n\r\n            byte[] header = new byte[6];\r\n\r\n            if (remote_is.read(header) != 6)\r\n                throw new IOException(\"Unexpected EOF on X11 startup!\");\r\n\r\n            if ((header[0] != 0x42) && (header[0] != 0x6c)) // 0x42 MSB first, 0x6C LSB first\r\n                throw new IOException(\"Unknown endian format in X11 message!\");\r\n\r\n\t\t\t/* Yes, I came up with this myself - shall I file an application for a patent? =) */\r\n\r\n            int idxMSB = (header[0] == 0x42) ? 0 : 1;\r\n\r\n\t\t\t/* Read authorization data header */\r\n\r\n            byte[] auth_buff = new byte[6];\r\n\r\n            if (remote_is.read(auth_buff) != 6)\r\n                throw new IOException(\"Unexpected EOF on X11 startup!\");\r\n\r\n            int authProtocolNameLength = ((auth_buff[idxMSB] & 0xff) << 8) | (auth_buff[1 - idxMSB] & 0xff);\r\n            int authProtocolDataLength = ((auth_buff[2 + idxMSB] & 0xff) << 8) | (auth_buff[3 - idxMSB] & 0xff);\r\n\r\n            if ((authProtocolNameLength > 256) || (authProtocolDataLength > 256))\r\n                throw new IOException(\"Buggy X11 authorization data\");\r\n\r\n            int authProtocolNamePadding = ((4 - (authProtocolNameLength % 4)) % 4);\r\n            int authProtocolDataPadding = ((4 - (authProtocolDataLength % 4)) % 4);\r\n\r\n            byte[] authProtocolName = new byte[authProtocolNameLength];\r\n            byte[] authProtocolData = new byte[authProtocolDataLength];\r\n\r\n            byte[] paddingBuffer = new byte[4];\r\n\r\n            if (remote_is.read(authProtocolName) != authProtocolNameLength)\r\n                throw new IOException(\"Unexpected EOF on X11 startup! (authProtocolName)\");\r\n\r\n            if (remote_is.read(paddingBuffer, 0, authProtocolNamePadding) != authProtocolNamePadding)\r\n                throw new IOException(\"Unexpected EOF on X11 startup! (authProtocolNamePadding)\");\r\n\r\n            if (remote_is.read(authProtocolData) != authProtocolDataLength)\r\n                throw new IOException(\"Unexpected EOF on X11 startup! (authProtocolData)\");\r\n\r\n            if (remote_is.read(paddingBuffer, 0, authProtocolDataPadding) != authProtocolDataPadding)\r\n                throw new IOException(\"Unexpected EOF on X11 startup! (authProtocolDataPadding)\");\r\n\r\n            if (\"MIT-MAGIC-COOKIE-1\".equals(new String(authProtocolName)) == false)\r\n                throw new IOException(\"Unknown X11 authorization protocol!\");\r\n\r\n            if (authProtocolDataLength != 16)\r\n                throw new IOException(\"Wrong data length for X11 authorization data!\");\r\n\r\n            StringBuffer tmp = new StringBuffer(32);\r\n            for (int i = 0; i < authProtocolData.length; i++) {\r\n                String digit2 = Integer.toHexString(authProtocolData[i] & 0xff);\r\n                tmp.append((digit2.length() == 2) ? digit2 : \"0\" + digit2);\r\n            }\r\n            String hexEncodedFakeCookie = tmp.toString();\r\n\r\n\t\t\t/* Order is very important here - it may be that a certain x11 forwarding\r\n\t\t\t * gets disabled right in the moment when we check and register our connection\r\n\t\t\t * */\r\n\r\n            synchronized (c) {\r\n\t\t\t\t/* Please read the comment in Channel.java */\r\n                c.hexX11FakeCookie = hexEncodedFakeCookie;\r\n            }\r\n\r\n\t\t\t/* Now check our fake cookie directory to see if we produced this cookie */\r\n\r\n            X11ServerData sd = c.cm.checkX11Cookie(hexEncodedFakeCookie);\r\n\r\n            if (sd == null)\r\n                throw new IOException(\"Invalid X11 cookie received.\");\r\n\r\n\t\t\t/* If the session which corresponds to this cookie is closed then we will\r\n\t\t\t * detect this: the session's close code will close all channels\r\n\t\t\t * with the session's assigned x11 fake cookie.\r\n\t\t\t */\r\n\r\n            s = new Socket(sd.hostname, sd.port);\r\n\r\n            OutputStream x11_os = s.getOutputStream();\r\n            InputStream x11_is = s.getInputStream();\r\n\r\n\t\t\t/* Now we are sending the startup packet to the real X11 server */\r\n\r\n            x11_os.write(header);\r\n\r\n            if (sd.x11_magic_cookie == null) {\r\n                byte[] emptyAuthData = new byte[6];\r\n\t\t\t\t/* empty auth data, hopefully you are connecting to localhost =) */\r\n                x11_os.write(emptyAuthData);\r\n            } else {\r\n                if (sd.x11_magic_cookie.length != 16)\r\n                    throw new IOException(\"The real X11 cookie has an invalid length!\");\r\n\r\n\t\t\t\t/* send X11 cookie specified by client */\r\n                x11_os.write(auth_buff);\r\n                x11_os.write(authProtocolName); /* re-use */\r\n                x11_os.write(paddingBuffer, 0, authProtocolNamePadding);\r\n                x11_os.write(sd.x11_magic_cookie);\r\n                x11_os.write(paddingBuffer, 0, authProtocolDataPadding);\r\n            }\r\n\r\n            x11_os.flush();\r\n\r\n\t\t\t/* Start forwarding traffic */\r\n\r\n            StreamForwarder r2l = new StreamForwarder(c, null, null, remote_is, x11_os, \"RemoteToX11\");\r\n            StreamForwarder l2r = new StreamForwarder(c, null, null, x11_is, remote_os, \"X11ToRemote\");\r\n\r\n\t\t\t/* No need to start two threads, one can be executed in the current thread */\r\n\r\n            r2l.setDaemon(true);\r\n            r2l.start();\r\n            l2r.run();\r\n\r\n            while (r2l.isAlive()) {\r\n                try {\r\n                    r2l.join();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n\r\n\t\t\t/* If the channel is already closed, then this is a no-op */\r\n\r\n            c.cm.closeChannel(c, \"EOF on both X11 streams reached.\", true);\r\n            s.close();\r\n        } catch (IOException e) {\r\n            log.log(50, \"IOException in X11 proxy code: \" + e.getMessage());\r\n\r\n            try {\r\n                c.cm.closeChannel(c, \"IOException in X11 proxy code (\" + e.getMessage() + \")\", true);\r\n            } catch (IOException e1) {\r\n            }\r\n            try {\r\n                if (s != null)\r\n                    s.close();\r\n            } catch (IOException e1) {\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/StreamForwarder.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.net.Socket;\r\n\r\n/**\r\n * A StreamForwarder forwards data between two given streams.\r\n * If two StreamForwarder threads are used (one for each direction)\r\n * then one can be configured to shutdown the underlying channel/socket\r\n * if both threads have finished forwarding (EOF).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: StreamForwarder.java,v 1.2 2006/02/13 21:19:25 cplattne Exp $\r\n */\r\npublic class StreamForwarder extends Thread {\r\n    OutputStream os;\r\n    InputStream is;\r\n    byte[] buffer = new byte[Channel.CHANNEL_BUFFER_SIZE];\r\n    Channel c;\r\n    StreamForwarder sibling;\r\n    Socket s;\r\n    String mode;\r\n\r\n    StreamForwarder(Channel c, StreamForwarder sibling, Socket s, InputStream is, OutputStream os, String mode)\r\n            throws IOException {\r\n        this.is = is;\r\n        this.os = os;\r\n        this.mode = mode;\r\n        this.c = c;\r\n        this.sibling = sibling;\r\n        this.s = s;\r\n    }\r\n\r\n    public void run() {\r\n        try {\r\n            while (true) {\r\n                int len = is.read(buffer);\r\n                if (len <= 0)\r\n                    break;\r\n                os.write(buffer, 0, len);\r\n                os.flush();\r\n            }\r\n        } catch (IOException ignore) {\r\n            try {\r\n                c.cm.closeChannel(c, \"Closed due to exception in StreamForwarder (\" + mode + \"): \"\r\n                        + ignore.getMessage(), true);\r\n            } catch (IOException e) {\r\n            }\r\n        } finally {\r\n            try {\r\n                os.close();\r\n            } catch (IOException e1) {\r\n            }\r\n            try {\r\n                is.close();\r\n            } catch (IOException e2) {\r\n            }\r\n\r\n            if (sibling != null) {\r\n                while (sibling.isAlive()) {\r\n                    try {\r\n                        sibling.join();\r\n                    } catch (InterruptedException e) {\r\n                    }\r\n                }\r\n\r\n                try {\r\n                    c.cm.closeChannel(c, \"StreamForwarder (\" + mode + \") is cleaning up the connection\", true);\r\n                } catch (IOException e3) {\r\n                }\r\n\r\n                try {\r\n                    if (s != null)\r\n                        s.close();\r\n                } catch (IOException e1) {\r\n                }\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/channel/X11ServerData.java",
    "content": "package ch.ethz.ssh2.channel;\r\n\r\n/**\r\n * X11ServerData. Data regarding an x11 forwarding target.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: X11ServerData.java,v 1.2 2005/08/29 14:26:21 cplattne Exp $\r\n */\r\npublic class X11ServerData {\r\n    public String hostname;\r\n    public int port;\r\n    public byte[] x11_magic_cookie; /* not the remote (fake) one, the local (real) one */\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/Base64.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\nimport java.io.CharArrayWriter;\r\nimport java.io.IOException;\r\n\r\n/**\r\n * Basic Base64 Support.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Base64.java,v 1.4 2005/08/11 12:47:31 cplattne Exp $\r\n */\r\npublic class Base64 {\r\n    static final char[] alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".toCharArray();\r\n\r\n    public static char[] encode(byte[] content) {\r\n        CharArrayWriter cw = new CharArrayWriter((4 * content.length) / 3);\r\n\r\n        int idx = 0;\r\n\r\n        int x = 0;\r\n\r\n        for (int i = 0; i < content.length; i++) {\r\n            if (idx == 0)\r\n                x = (content[i] & 0xff) << 16;\r\n            else if (idx == 1)\r\n                x = x | ((content[i] & 0xff) << 8);\r\n            else\r\n                x = x | (content[i] & 0xff);\r\n\r\n            idx++;\r\n\r\n            if (idx == 3) {\r\n                cw.write(alphabet[x >> 18]);\r\n                cw.write(alphabet[(x >> 12) & 0x3f]);\r\n                cw.write(alphabet[(x >> 6) & 0x3f]);\r\n                cw.write(alphabet[x & 0x3f]);\r\n\r\n                idx = 0;\r\n            }\r\n        }\r\n\r\n        if (idx == 1) {\r\n            cw.write(alphabet[x >> 18]);\r\n            cw.write(alphabet[(x >> 12) & 0x3f]);\r\n            cw.write('=');\r\n            cw.write('=');\r\n        }\r\n\r\n        if (idx == 2) {\r\n            cw.write(alphabet[x >> 18]);\r\n            cw.write(alphabet[(x >> 12) & 0x3f]);\r\n            cw.write(alphabet[(x >> 6) & 0x3f]);\r\n            cw.write('=');\r\n        }\r\n\r\n        return cw.toCharArray();\r\n    }\r\n\r\n    public static byte[] decode(char[] message) throws IOException {\r\n        byte buff[] = new byte[4];\r\n        byte dest[] = new byte[message.length];\r\n\r\n        int bpos = 0;\r\n        int destpos = 0;\r\n\r\n        for (int i = 0; i < message.length; i++) {\r\n            int c = message[i];\r\n\r\n            if ((c == '\\n') || (c == '\\r') || (c == ' ') || (c == '\\t'))\r\n                continue;\r\n\r\n            if ((c >= 'A') && (c <= 'Z')) {\r\n                buff[bpos++] = (byte) (c - 'A');\r\n            } else if ((c >= 'a') && (c <= 'z')) {\r\n                buff[bpos++] = (byte) ((c - 'a') + 26);\r\n            } else if ((c >= '0') && (c <= '9')) {\r\n                buff[bpos++] = (byte) ((c - '0') + 52);\r\n            } else if (c == '+') {\r\n                buff[bpos++] = 62;\r\n            } else if (c == '/') {\r\n                buff[bpos++] = 63;\r\n            } else if (c == '=') {\r\n                buff[bpos++] = 64;\r\n            } else {\r\n                throw new IOException(\"Illegal char in base64 code.\");\r\n            }\r\n\r\n            if (bpos == 4) {\r\n                bpos = 0;\r\n\r\n                if (buff[0] == 64)\r\n                    break;\r\n\r\n                if (buff[1] == 64)\r\n                    throw new IOException(\"Unexpected '=' in base64 code.\");\r\n\r\n                if (buff[2] == 64) {\r\n                    int v = (((buff[0] & 0x3f) << 6) | ((buff[1] & 0x3f)));\r\n                    dest[destpos++] = (byte) (v >> 4);\r\n                    break;\r\n                } else if (buff[3] == 64) {\r\n                    int v = (((buff[0] & 0x3f) << 12) | ((buff[1] & 0x3f) << 6) | ((buff[2] & 0x3f)));\r\n                    dest[destpos++] = (byte) (v >> 10);\r\n                    dest[destpos++] = (byte) (v >> 2);\r\n                    break;\r\n                } else {\r\n                    int v = (((buff[0] & 0x3f) << 18) | ((buff[1] & 0x3f) << 12) | ((buff[2] & 0x3f) << 6) | ((buff[3] & 0x3f)));\r\n                    dest[destpos++] = (byte) (v >> 16);\r\n                    dest[destpos++] = (byte) (v >> 8);\r\n                    dest[destpos++] = (byte) (v);\r\n                }\r\n            }\r\n        }\r\n\r\n        byte[] res = new byte[destpos];\r\n        System.arraycopy(dest, 0, res, 0, destpos);\r\n\r\n        return res;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/CryptoWishList.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;\r\nimport ch.ethz.ssh2.crypto.digest.MAC;\r\nimport ch.ethz.ssh2.transport.KexManager;\r\n\r\n/**\r\n * CryptoWishList.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: CryptoWishList.java,v 1.3 2005/08/24 17:54:10 cplattne Exp $\r\n */\r\npublic class CryptoWishList {\r\n    public String[] kexAlgorithms = KexManager.getDefaultKexAlgorithmList();\r\n    public String[] serverHostKeyAlgorithms = KexManager.getDefaultServerHostkeyAlgorithmList();\r\n    public String[] c2s_enc_algos = BlockCipherFactory.getDefaultCipherList();\r\n    public String[] s2c_enc_algos = BlockCipherFactory.getDefaultCipherList();\r\n    public String[] c2s_mac_algos = MAC.getMacList();\r\n    public String[] s2c_mac_algos = MAC.getMacList();\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/KeyMaterial.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\n\r\nimport ch.ethz.ssh2.crypto.digest.HashForSSH2Types;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * Establishes key material for iv/key/mac (both directions).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: KeyMaterial.java,v 1.2 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class KeyMaterial {\r\n    public byte[] initial_iv_client_to_server;\r\n    public byte[] initial_iv_server_to_client;\r\n    public byte[] enc_key_client_to_server;\r\n    public byte[] enc_key_server_to_client;\r\n    public byte[] integrity_key_client_to_server;\r\n    public byte[] integrity_key_server_to_client;\r\n\r\n    private static byte[] calculateKey(HashForSSH2Types sh, BigInteger K, byte[] H, byte type, byte[] SessionID,\r\n                                       int keyLength) {\r\n        byte[] res = new byte[keyLength];\r\n\r\n        int dglen = sh.getDigestLength();\r\n        int numRounds = (keyLength + dglen - 1) / dglen;\r\n\r\n        byte[][] tmp = new byte[numRounds][];\r\n\r\n        sh.reset();\r\n        sh.updateBigInt(K);\r\n        sh.updateBytes(H);\r\n        sh.updateByte(type);\r\n        sh.updateBytes(SessionID);\r\n\r\n        tmp[0] = sh.getDigest();\r\n\r\n        int off = 0;\r\n        int produced = Math.min(dglen, keyLength);\r\n\r\n        System.arraycopy(tmp[0], 0, res, off, produced);\r\n\r\n        keyLength -= produced;\r\n        off += produced;\r\n\r\n        for (int i = 1; i < numRounds; i++) {\r\n            sh.updateBigInt(K);\r\n            sh.updateBytes(H);\r\n\r\n            for (int j = 0; j < i; j++)\r\n                sh.updateBytes(tmp[j]);\r\n\r\n            tmp[i] = sh.getDigest();\r\n\r\n            produced = Math.min(dglen, keyLength);\r\n            System.arraycopy(tmp[i], 0, res, off, produced);\r\n            keyLength -= produced;\r\n            off += produced;\r\n        }\r\n\r\n        return res;\r\n    }\r\n\r\n    public static KeyMaterial create(String hashType, byte[] H, BigInteger K, byte[] SessionID, int keyLengthCS,\r\n                                     int blockSizeCS, int macLengthCS, int keyLengthSC, int blockSizeSC, int macLengthSC)\r\n            throws IllegalArgumentException {\r\n        KeyMaterial km = new KeyMaterial();\r\n\r\n        HashForSSH2Types sh = new HashForSSH2Types(hashType);\r\n\r\n        km.initial_iv_client_to_server = calculateKey(sh, K, H, (byte) 'A', SessionID, blockSizeCS);\r\n\r\n        km.initial_iv_server_to_client = calculateKey(sh, K, H, (byte) 'B', SessionID, blockSizeSC);\r\n\r\n        km.enc_key_client_to_server = calculateKey(sh, K, H, (byte) 'C', SessionID, keyLengthCS);\r\n\r\n        km.enc_key_server_to_client = calculateKey(sh, K, H, (byte) 'D', SessionID, keyLengthSC);\r\n\r\n        km.integrity_key_client_to_server = calculateKey(sh, K, H, (byte) 'E', SessionID, macLengthCS);\r\n\r\n        km.integrity_key_server_to_client = calculateKey(sh, K, H, (byte) 'F', SessionID, macLengthSC);\r\n\r\n        return km;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/PEMDecoder.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\nimport ch.ethz.ssh2.crypto.cipher.*;\r\nimport ch.ethz.ssh2.crypto.digest.MD5;\r\nimport ch.ethz.ssh2.signature.DSAPrivateKey;\r\nimport ch.ethz.ssh2.signature.RSAPrivateKey;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.CharArrayReader;\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PEM Support.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PEMDecoder.java,v 1.7 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\npublic class PEMDecoder {\r\n    private static final int PEM_RSA_PRIVATE_KEY = 1;\r\n    private static final int PEM_DSA_PRIVATE_KEY = 2;\r\n\r\n    private static final int hexToInt(char c) {\r\n        if ((c >= 'a') && (c <= 'f')) {\r\n            return (c - 'a') + 10;\r\n        }\r\n\r\n        if ((c >= 'A') && (c <= 'F')) {\r\n            return (c - 'A') + 10;\r\n        }\r\n\r\n        if ((c >= '0') && (c <= '9')) {\r\n            return (c - '0');\r\n        }\r\n\r\n        throw new IllegalArgumentException(\"Need hex char\");\r\n    }\r\n\r\n    private static byte[] hexToByteArray(String hex) {\r\n        if (hex == null)\r\n            throw new IllegalArgumentException(\"null argument\");\r\n\r\n        if ((hex.length() % 2) != 0)\r\n            throw new IllegalArgumentException(\"Uneven string length in hex encoding.\");\r\n\r\n        byte decoded[] = new byte[hex.length() / 2];\r\n\r\n        for (int i = 0; i < decoded.length; i++) {\r\n            int hi = hexToInt(hex.charAt(i * 2));\r\n            int lo = hexToInt(hex.charAt((i * 2) + 1));\r\n\r\n            decoded[i] = (byte) (hi * 16 + lo);\r\n        }\r\n\r\n        return decoded;\r\n    }\r\n\r\n    private static byte[] generateKeyFromPasswordSaltWithMD5(byte[] password, byte[] salt, int keyLen)\r\n            throws IOException {\r\n        if (salt.length < 8)\r\n            throw new IllegalArgumentException(\"Salt needs to be at least 8 bytes for key generation.\");\r\n\r\n        MD5 md5 = new MD5();\r\n\r\n        byte[] key = new byte[keyLen];\r\n        byte[] tmp = new byte[md5.getDigestLength()];\r\n\r\n        while (true) {\r\n            md5.update(password, 0, password.length);\r\n            md5.update(salt, 0, 8); // ARGH we only use the first 8 bytes of the salt in this step.\r\n            // This took me two hours until I got AES-xxx running.\r\n\r\n            int copy = (keyLen < tmp.length) ? keyLen : tmp.length;\r\n\r\n            md5.digest(tmp, 0);\r\n\r\n            System.arraycopy(tmp, 0, key, key.length - keyLen, copy);\r\n\r\n            keyLen -= copy;\r\n\r\n            if (keyLen == 0)\r\n                return key;\r\n\r\n            md5.update(tmp, 0, tmp.length);\r\n        }\r\n    }\r\n\r\n    private static byte[] removePadding(byte[] buff, int blockSize) throws IOException {\r\n        /* Removes RFC 1423/PKCS #7 padding */\r\n\r\n        int rfc_1423_padding = buff[buff.length - 1] & 0xff;\r\n\r\n        if ((rfc_1423_padding < 1) || (rfc_1423_padding > blockSize))\r\n            throw new IOException(\"Decrypted PEM has wrong padding, did you specify the correct password?\");\r\n\r\n        for (int i = 2; i <= rfc_1423_padding; i++) {\r\n            if (buff[buff.length - i] != rfc_1423_padding)\r\n                throw new IOException(\"Decrypted PEM has wrong padding, did you specify the correct password?\");\r\n        }\r\n\r\n        byte[] tmp = new byte[buff.length - rfc_1423_padding];\r\n        System.arraycopy(buff, 0, tmp, 0, buff.length - rfc_1423_padding);\r\n        return tmp;\r\n    }\r\n\r\n    private static final PEMStructure parsePEM(char[] pem) throws IOException {\r\n        PEMStructure ps = new PEMStructure();\r\n\r\n        String line = null;\r\n\r\n        BufferedReader br = new BufferedReader(new CharArrayReader(pem));\r\n\r\n        String endLine = null;\r\n\r\n        while (true) {\r\n            line = br.readLine();\r\n\r\n            if (line == null)\r\n                throw new IOException(\"Invalid PEM structure, '-----BEGIN...' missing\");\r\n\r\n            line = line.trim();\r\n\r\n            if (line.startsWith(\"-----BEGIN DSA PRIVATE KEY-----\")) {\r\n                endLine = \"-----END DSA PRIVATE KEY-----\";\r\n                ps.pemType = PEM_DSA_PRIVATE_KEY;\r\n                break;\r\n            }\r\n\r\n            if (line.startsWith(\"-----BEGIN RSA PRIVATE KEY-----\")) {\r\n                endLine = \"-----END RSA PRIVATE KEY-----\";\r\n                ps.pemType = PEM_RSA_PRIVATE_KEY;\r\n                break;\r\n            }\r\n        }\r\n\r\n        while (true) {\r\n            line = br.readLine();\r\n\r\n            if (line == null)\r\n                throw new IOException(\"Invalid PEM structure, \" + endLine + \" missing\");\r\n\r\n            line = line.trim();\r\n\r\n            int sem_idx = line.indexOf(':');\r\n\r\n            if (sem_idx == -1)\r\n                break;\r\n\r\n            String name = line.substring(0, sem_idx + 1);\r\n            String value = line.substring(sem_idx + 1);\r\n\r\n            String values[] = value.split(\",\");\r\n\r\n            for (int i = 0; i < values.length; i++)\r\n                values[i] = values[i].trim();\r\n\r\n            // Proc-Type: 4,ENCRYPTED\r\n            // DEK-Info: DES-EDE3-CBC,579B6BE3E5C60483\r\n\r\n            if (\"Proc-Type:\".equals(name)) {\r\n                ps.procType = values;\r\n                continue;\r\n            }\r\n\r\n            if (\"DEK-Info:\".equals(name)) {\r\n                ps.dekInfo = values;\r\n                continue;\r\n            }\r\n\t\t\t/* Ignore line */\r\n        }\r\n\r\n        StringBuffer keyData = new StringBuffer();\r\n\r\n        while (true) {\r\n            if (line == null)\r\n                throw new IOException(\"Invalid PEM structure, \" + endLine + \" missing\");\r\n\r\n            line = line.trim();\r\n\r\n            if (line.startsWith(endLine))\r\n                break;\r\n\r\n            keyData.append(line);\r\n\r\n            line = br.readLine();\r\n        }\r\n\r\n        char[] pem_chars = new char[keyData.length()];\r\n        keyData.getChars(0, pem_chars.length, pem_chars, 0);\r\n\r\n        ps.data = Base64.decode(pem_chars);\r\n\r\n        if (ps.data.length == 0)\r\n            throw new IOException(\"Invalid PEM structure, no data available\");\r\n\r\n        return ps;\r\n    }\r\n\r\n    private static final void decryptPEM(PEMStructure ps, byte[] pw) throws IOException {\r\n        if (ps.dekInfo == null)\r\n            throw new IOException(\"Broken PEM, no mode and salt given, but encryption enabled\");\r\n\r\n        if (ps.dekInfo.length != 2)\r\n            throw new IOException(\"Broken PEM, DEK-Info is incomplete!\");\r\n\r\n        String algo = ps.dekInfo[0];\r\n        byte[] salt = hexToByteArray(ps.dekInfo[1]);\r\n\r\n        BlockCipher bc = null;\r\n\r\n        if (algo.equals(\"DES-EDE3-CBC\")) {\r\n            DESede des3 = new DESede();\r\n            des3.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24));\r\n            bc = new CBCMode(des3, salt, false);\r\n        } else if (algo.equals(\"DES-CBC\")) {\r\n            DES des = new DES();\r\n            des.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 8));\r\n            bc = new CBCMode(des, salt, false);\r\n        } else if (algo.equals(\"AES-128-CBC\")) {\r\n            AES aes = new AES();\r\n            aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 16));\r\n            bc = new CBCMode(aes, salt, false);\r\n        } else if (algo.equals(\"AES-192-CBC\")) {\r\n            AES aes = new AES();\r\n            aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 24));\r\n            bc = new CBCMode(aes, salt, false);\r\n        } else if (algo.equals(\"AES-256-CBC\")) {\r\n            AES aes = new AES();\r\n            aes.init(false, generateKeyFromPasswordSaltWithMD5(pw, salt, 32));\r\n            bc = new CBCMode(aes, salt, false);\r\n        } else {\r\n            throw new IOException(\"Cannot decrypt PEM structure, unknown cipher \" + algo);\r\n        }\r\n\r\n        if ((ps.data.length % bc.getBlockSize()) != 0)\r\n            throw new IOException(\"Invalid PEM structure, size of encrypted block is not a multiple of \"\r\n                    + bc.getBlockSize());\r\n\r\n\t\t/* Now decrypt the content */\r\n\r\n        byte[] dz = new byte[ps.data.length];\r\n\r\n        for (int i = 0; i < ps.data.length / bc.getBlockSize(); i++) {\r\n            bc.transformBlock(ps.data, i * bc.getBlockSize(), dz, i * bc.getBlockSize());\r\n        }\r\n\r\n\t\t/* Now check and remove RFC 1423/PKCS #7 padding */\r\n\r\n        dz = removePadding(dz, bc.getBlockSize());\r\n\r\n        ps.data = dz;\r\n        ps.dekInfo = null;\r\n        ps.procType = null;\r\n    }\r\n\r\n    public static final boolean isPEMEncrypted(PEMStructure ps) throws IOException {\r\n        if (ps.procType == null)\r\n            return false;\r\n\r\n        if (ps.procType.length != 2)\r\n            throw new IOException(\"Unknown Proc-Type field.\");\r\n\r\n        if (\"4\".equals(ps.procType[0]) == false)\r\n            throw new IOException(\"Unknown Proc-Type field (\" + ps.procType[0] + \")\");\r\n\r\n        if (\"ENCRYPTED\".equals(ps.procType[1]))\r\n            return true;\r\n\r\n        return false;\r\n    }\r\n\r\n    public static Object decode(char[] pem, String password) throws IOException {\r\n        PEMStructure ps = parsePEM(pem);\r\n\r\n        if (isPEMEncrypted(ps)) {\r\n            if (password == null)\r\n                throw new IOException(\"PEM is encrypted, but no password was specified\");\r\n\r\n            decryptPEM(ps, password.getBytes());\r\n        }\r\n\r\n        if (ps.pemType == PEM_DSA_PRIVATE_KEY) {\r\n            SimpleDERReader dr = new SimpleDERReader(ps.data);\r\n\r\n            byte[] seq = dr.readSequenceAsByteArray();\r\n\r\n            if (dr.available() != 0)\r\n                throw new IOException(\"Padding in DSA PRIVATE KEY DER stream.\");\r\n\r\n            dr.resetInput(seq);\r\n\r\n            BigInteger version = dr.readInt();\r\n\r\n            if (version.compareTo(BigInteger.ZERO) != 0)\r\n                throw new IOException(\"Wrong version (\" + version + \") in DSA PRIVATE KEY DER stream.\");\r\n\r\n            BigInteger p = dr.readInt();\r\n            BigInteger q = dr.readInt();\r\n            BigInteger g = dr.readInt();\r\n            BigInteger y = dr.readInt();\r\n            BigInteger x = dr.readInt();\r\n\r\n            if (dr.available() != 0)\r\n                throw new IOException(\"Padding in DSA PRIVATE KEY DER stream.\");\r\n\r\n            return new DSAPrivateKey(p, q, g, y, x);\r\n        }\r\n\r\n        if (ps.pemType == PEM_RSA_PRIVATE_KEY) {\r\n            SimpleDERReader dr = new SimpleDERReader(ps.data);\r\n\r\n            byte[] seq = dr.readSequenceAsByteArray();\r\n\r\n            if (dr.available() != 0)\r\n                throw new IOException(\"Padding in RSA PRIVATE KEY DER stream.\");\r\n\r\n            dr.resetInput(seq);\r\n\r\n            BigInteger version = dr.readInt();\r\n\r\n            if ((version.compareTo(BigInteger.ZERO) != 0) && (version.compareTo(BigInteger.ONE) != 0))\r\n                throw new IOException(\"Wrong version (\" + version + \") in RSA PRIVATE KEY DER stream.\");\r\n\r\n            BigInteger n = dr.readInt();\r\n            BigInteger e = dr.readInt();\r\n            BigInteger d = dr.readInt();\r\n\r\n            return new RSAPrivateKey(d, e, n);\r\n        }\r\n\r\n        throw new IOException(\"PEM problem: it is of unknown type\");\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/PEMStructure.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\n/**\r\n * Parsed PEM structure.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PEMStructure.java,v 1.1 2005/08/11 12:47:31 cplattne Exp $\r\n */\r\n\r\npublic class PEMStructure {\r\n    int pemType;\r\n    String dekInfo[];\r\n    String procType[];\r\n    byte[] data;\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/SimpleDERReader.java",
    "content": "package ch.ethz.ssh2.crypto;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * SimpleDERReader.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SimpleDERReader.java,v 1.3 2006/08/11 12:24:00 cplattne Exp $\r\n */\r\npublic class SimpleDERReader {\r\n    byte[] buffer;\r\n    int pos;\r\n    int count;\r\n\r\n    public SimpleDERReader(byte[] b) {\r\n        resetInput(b);\r\n    }\r\n\r\n    public SimpleDERReader(byte[] b, int off, int len) {\r\n        resetInput(b, off, len);\r\n    }\r\n\r\n    public void resetInput(byte[] b) {\r\n        resetInput(b, 0, b.length);\r\n    }\r\n\r\n    public void resetInput(byte[] b, int off, int len) {\r\n        buffer = b;\r\n        pos = off;\r\n        count = len;\r\n    }\r\n\r\n    private byte readByte() throws IOException {\r\n        if (count <= 0)\r\n            throw new IOException(\"DER byte array: out of data\");\r\n        count--;\r\n        return buffer[pos++];\r\n    }\r\n\r\n    private byte[] readBytes(int len) throws IOException {\r\n        if (len > count)\r\n            throw new IOException(\"DER byte array: out of data\");\r\n\r\n        byte[] b = new byte[len];\r\n\r\n        System.arraycopy(buffer, pos, b, 0, len);\r\n\r\n        pos += len;\r\n        count -= len;\r\n\r\n        return b;\r\n    }\r\n\r\n    public int available() {\r\n        return count;\r\n    }\r\n\r\n    private int readLength() throws IOException {\r\n        int len = readByte() & 0xff;\r\n\r\n        if ((len & 0x80) == 0)\r\n            return len;\r\n\r\n        int remain = len & 0x7F;\r\n\r\n        if (remain == 0)\r\n            return -1;\r\n\r\n        len = 0;\r\n\r\n        while (remain > 0) {\r\n            len = len << 8;\r\n            len = len | (readByte() & 0xff);\r\n            remain--;\r\n        }\r\n\r\n        return len;\r\n    }\r\n\r\n    public int ignoreNextObject() throws IOException {\r\n        int type = readByte() & 0xff;\r\n\r\n        int len = readLength();\r\n\r\n        if ((len < 0) || len > available())\r\n            throw new IOException(\"Illegal len in DER object (\" + len + \")\");\r\n\r\n        readBytes(len);\r\n\r\n        return type;\r\n    }\r\n\r\n    public BigInteger readInt() throws IOException {\r\n        int type = readByte() & 0xff;\r\n\r\n        if (type != 0x02)\r\n            throw new IOException(\"Expected DER Integer, but found type \" + type);\r\n\r\n        int len = readLength();\r\n\r\n        if ((len < 0) || len > available())\r\n            throw new IOException(\"Illegal len in DER object (\" + len + \")\");\r\n\r\n        byte[] b = readBytes(len);\r\n\r\n        BigInteger bi = new BigInteger(b);\r\n\r\n        return bi;\r\n    }\r\n\r\n    public byte[] readSequenceAsByteArray() throws IOException {\r\n        int type = readByte() & 0xff;\r\n\r\n        if (type != 0x30)\r\n            throw new IOException(\"Expected DER Sequence, but found type \" + type);\r\n\r\n        int len = readLength();\r\n\r\n        if ((len < 0) || len > available())\r\n            throw new IOException(\"Illegal len in DER object (\" + len + \")\");\r\n\r\n        byte[] b = readBytes(len);\r\n\r\n        return b;\r\n    }\r\n\r\n    public byte[] readOctetString() throws IOException {\r\n        int type = readByte() & 0xff;\r\n\r\n        if (type != 0x04)\r\n            throw new IOException(\"Expected DER Octetstring, but found type \" + type);\r\n\r\n        int len = readLength();\r\n\r\n        if ((len < 0) || len > available())\r\n            throw new IOException(\"Illegal len in DER object (\" + len + \")\");\r\n\r\n        byte[] b = readBytes(len);\r\n\r\n        return b;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/AES.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/*\r\n This file was shamelessly taken from the Bouncy Castle Crypto package.\r\n Their licence file states the following:\r\n\r\n Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle\r\n (http://www.bouncycastle.org)\r\n\r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n\r\n The above copyright notice and this permission notice shall be included in\r\n all copies or substantial portions of the Software.\r\n\r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n THE SOFTWARE. \r\n */\r\n\r\n/**\r\n * An implementation of the AES (Rijndael), from FIPS-197.\r\n * <p>\r\n * For further details see: <a\r\n * href=\"http://csrc.nist.gov/encryption/aes/\">http://csrc.nist.gov/encryption/aes/\r\n * </a>.\r\n * <p>\r\n * This implementation is based on optimizations from Dr. Brian Gladman's paper\r\n * and C code at <a\r\n * href=\"http://fp.gladman.plus.com/cryptography_technology/rijndael/\">http://fp.gladman.plus.com/cryptography_technology/rijndael/\r\n * </a>\r\n * <p>\r\n * There are three levels of tradeoff of speed vs memory Because java has no\r\n * preprocessor, they are written as three separate classes from which to choose\r\n * <p>\r\n * The fastest uses 8Kbytes of static tables to precompute round calculations, 4\r\n * 256 word tables for encryption and 4 for decryption.\r\n * <p>\r\n * The middle performance version uses only one 256 word table for each, for a\r\n * total of 2Kbytes, adding 12 rotate operations per round to compute the values\r\n * contained in the other tables from the contents of the first\r\n * <p>\r\n * The slowest version uses no static tables at all and computes the values in\r\n * each round\r\n * <p>\r\n * This file contains the fast version with 8Kbytes of static tables for round\r\n * precomputation\r\n *\r\n * @author See comments in the source file\r\n * @version $Id: AES.java,v 1.4 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\npublic class AES implements BlockCipher {\r\n    // The S box\r\n    private static final byte[] S = {(byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107,\r\n            (byte) 111, (byte) 197, (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171,\r\n            (byte) 118, (byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240,\r\n            (byte) 173, (byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, (byte) 183,\r\n            (byte) 253, (byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, (byte) 52, (byte) 165,\r\n            (byte) 229, (byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, (byte) 4, (byte) 199, (byte) 35,\r\n            (byte) 195, (byte) 24, (byte) 150, (byte) 5, (byte) 154, (byte) 7, (byte) 18, (byte) 128, (byte) 226,\r\n            (byte) 235, (byte) 39, (byte) 178, (byte) 117, (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27,\r\n            (byte) 110, (byte) 90, (byte) 160, (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227,\r\n            (byte) 47, (byte) 132, (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177,\r\n            (byte) 91, (byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207,\r\n            (byte) 208, (byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, (byte) 69,\r\n            (byte) 249, (byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, (byte) 81, (byte) 163,\r\n            (byte) 64, (byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, (byte) 188, (byte) 182, (byte) 218,\r\n            (byte) 33, (byte) 16, (byte) 255, (byte) 243, (byte) 210, (byte) 205, (byte) 12, (byte) 19, (byte) 236,\r\n            (byte) 95, (byte) 151, (byte) 68, (byte) 23, (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100,\r\n            (byte) 93, (byte) 25, (byte) 115, (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42,\r\n            (byte) 144, (byte) 136, (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11,\r\n            (byte) 219, (byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92,\r\n            (byte) 194, (byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, (byte) 231,\r\n            (byte) 200, (byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, (byte) 108, (byte) 86,\r\n            (byte) 244, (byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, (byte) 186, (byte) 120, (byte) 37,\r\n            (byte) 46, (byte) 28, (byte) 166, (byte) 180, (byte) 198, (byte) 232, (byte) 221, (byte) 116, (byte) 31,\r\n            (byte) 75, (byte) 189, (byte) 139, (byte) 138, (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72,\r\n            (byte) 3, (byte) 246, (byte) 14, (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193,\r\n            (byte) 29, (byte) 158, (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142,\r\n            (byte) 148, (byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223,\r\n            (byte) 140, (byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, (byte) 65,\r\n            (byte) 153, (byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22,};\r\n\r\n    // The inverse S-box\r\n    private static final byte[] Si = {(byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165,\r\n            (byte) 56, (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251,\r\n            (byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, (byte) 52,\r\n            (byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, (byte) 84, (byte) 123,\r\n            (byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, (byte) 238, (byte) 76, (byte) 149,\r\n            (byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, (byte) 8, (byte) 46, (byte) 161, (byte) 102,\r\n            (byte) 40, (byte) 217, (byte) 36, (byte) 178, (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109,\r\n            (byte) 139, (byte) 209, (byte) 37, (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104,\r\n            (byte) 152, (byte) 22, (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182,\r\n            (byte) 146, (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218,\r\n            (byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, (byte) 144,\r\n            (byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, (byte) 247, (byte) 228,\r\n            (byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, (byte) 208, (byte) 44, (byte) 30,\r\n            (byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, (byte) 193, (byte) 175, (byte) 189, (byte) 3,\r\n            (byte) 1, (byte) 19, (byte) 138, (byte) 107, (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79,\r\n            (byte) 103, (byte) 220, (byte) 234, (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180,\r\n            (byte) 230, (byte) 115, (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53,\r\n            (byte) 133, (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110,\r\n            (byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, (byte) 111,\r\n            (byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, (byte) 252, (byte) 86,\r\n            (byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, (byte) 154, (byte) 219, (byte) 192,\r\n            (byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, (byte) 31, (byte) 221, (byte) 168, (byte) 51,\r\n            (byte) 136, (byte) 7, (byte) 199, (byte) 49, (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39,\r\n            (byte) 128, (byte) 236, (byte) 95, (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181,\r\n            (byte) 74, (byte) 13, (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156,\r\n            (byte) 239, (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176,\r\n            (byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, (byte) 23,\r\n            (byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, (byte) 225, (byte) 105,\r\n            (byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125,};\r\n\r\n    // vector used in calculating key schedule (powers of x in GF(256))\r\n    private static final int[] rcon = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,\r\n            0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91};\r\n\r\n    // precomputation tables of calculations for rounds\r\n    private static final int[] T0 = {0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6,\r\n            0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,\r\n            0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,\r\n            0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, 0xc2b7b775,\r\n            0x1cfdfde1, 0xae93933d, 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, 0x5c343468, 0xf4a5a551,\r\n            0x34e5e5d1, 0x08f1f1f9, 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, 0x65232346,\r\n            0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,\r\n            0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36,\r\n            0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, 0x7b292952, 0x3ee3e3dd,\r\n            0x712f2f5e, 0x97848413, 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, 0x1ffcfce3, 0xc8b1b179,\r\n            0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,\r\n            0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,\r\n            0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d,\r\n            0xc0404080, 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf,\r\n            0x63212142, 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,\r\n            0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, 0xac6464c8,\r\n            0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,\r\n            0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16,\r\n            0x76dbdbad, 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,\r\n            0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, 0x32e7e7d5,\r\n            0x43c8c88b, 0x5937376e, 0xb76d6dda, 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, 0xfa5656ac,\r\n            0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,\r\n            0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,\r\n            0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, 0xd8484890,\r\n            0x05030306, 0x01f6f6f7, 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, 0x91868617, 0x58c1c199,\r\n            0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, 0x898e8e07,\r\n            0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,\r\n            0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182,\r\n            0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c};\r\n\r\n    private static final int[] T1 = {0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd,\r\n            0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,\r\n            0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,\r\n            0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, 0xb7b775c2,\r\n            0xfdfde11c, 0x93933dae, 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, 0x3434685c, 0xa5a551f4,\r\n            0xe5e5d134, 0xf1f1f908, 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, 0x23234665,\r\n            0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,\r\n            0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d,\r\n            0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, 0x2929527b, 0xe3e3dd3e,\r\n            0x2f2f5e71, 0x84841397, 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, 0xfcfce31f, 0xb1b179c8,\r\n            0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,\r\n            0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf,\r\n            0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe,\r\n            0x404080c0, 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, 0xbcbc63df, 0xb6b677c1, 0xdadaaf75,\r\n            0x21214263, 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,\r\n            0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, 0x6464c8ac,\r\n            0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,\r\n            0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d,\r\n            0xdbdbad76, 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,\r\n            0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, 0xe7e7d532,\r\n            0xc8c88b43, 0x37376e59, 0x6d6ddab7, 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, 0x5656acfa,\r\n            0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f,\r\n            0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,\r\n            0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, 0x484890d8,\r\n            0x03030605, 0xf6f6f701, 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, 0x86861791, 0xc1c19958,\r\n            0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, 0x8e8e0789,\r\n            0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,\r\n            0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3,\r\n            0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a};\r\n\r\n    private static final int[] T2 = {0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b,\r\n            0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,\r\n            0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,\r\n            0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, 0xb775c2b7,\r\n            0xfde11cfd, 0x933dae93, 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, 0x34685c34, 0xa551f4a5,\r\n            0xe5d134e5, 0xf1f908f1, 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, 0x23466523,\r\n            0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,\r\n            0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b,\r\n            0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, 0x29527b29, 0xe3dd3ee3,\r\n            0x2f5e712f, 0x84139784, 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, 0xfce31ffc, 0xb179c8b1,\r\n            0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,\r\n            0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45,\r\n            0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3,\r\n            0x4080c040, 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da,\r\n            0x21426321, 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,\r\n            0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, 0x64c8ac64,\r\n            0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,\r\n            0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b,\r\n            0xdbad76db, 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,\r\n            0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, 0xe7d532e7,\r\n            0xc88b43c8, 0x376e5937, 0x6ddab76d, 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, 0x56acfa56,\r\n            0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25,\r\n            0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,\r\n            0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, 0x4890d848,\r\n            0x03060503, 0xf6f701f6, 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, 0x86179186, 0xc19958c1,\r\n            0x1d3a271d, 0x9e27b99e, 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, 0x8e07898e,\r\n            0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,\r\n            0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341,\r\n            0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16};\r\n\r\n    private static final int[] T3 = {0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b,\r\n            0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,\r\n            0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,\r\n            0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7,\r\n            0xe11cfdfd, 0x3dae9393, 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, 0x685c3434, 0x51f4a5a5,\r\n            0xd134e5e5, 0xf908f1f1, 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, 0x46652323,\r\n            0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,\r\n            0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b,\r\n            0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3,\r\n            0x5e712f2f, 0x13978484, 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, 0xe31ffcfc, 0x79c8b1b1,\r\n            0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,\r\n            0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545,\r\n            0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3,\r\n            0x80c04040, 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada,\r\n            0x42632121, 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,\r\n            0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, 0xc8ac6464,\r\n            0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,\r\n            0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b,\r\n            0xad76dbdb, 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,\r\n            0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, 0xd532e7e7,\r\n            0x8b43c8c8, 0x6e593737, 0xdab76d6d, 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, 0xacfa5656,\r\n            0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525,\r\n            0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,\r\n            0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, 0x90d84848,\r\n            0x06050303, 0xf701f6f6, 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, 0x17918686, 0x9958c1c1,\r\n            0x3a271d1d, 0x27b99e9e, 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, 0x07898e8e,\r\n            0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,\r\n            0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141,\r\n            0x29b09999, 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616};\r\n\r\n    private static final int[] Tinv0 = {0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f,\r\n            0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,\r\n            0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b,\r\n            0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, 0x6a89c275,\r\n            0x78798ef4, 0x6b3e5899, 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, 0x184adf63, 0x82311ae5,\r\n            0x60335197, 0x457f5362, 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, 0x876cde94,\r\n            0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,\r\n            0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65,\r\n            0xd5be0506, 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, 0x39ec830b, 0xaaef6040,\r\n            0x069f715e, 0x51106ebd, 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, 0x055dc471, 0x6fd40604,\r\n            0xff155060, 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879,\r\n            0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,\r\n            0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793,\r\n            0xd296eeb4, 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, 0x0aba93e2, 0xe52aa0c0, 0x43e0223c,\r\n            0x1d171b12, 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3,\r\n            0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, 0xcadc31d7,\r\n            0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,\r\n            0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56,\r\n            0xef903322, 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f,\r\n            0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, 0xbe805d9f,\r\n            0x7c93d069, 0xa92dd56f, 0xb31225cf, 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, 0xf418596e,\r\n            0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,\r\n            0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733,\r\n            0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, 0xe3b5d19e,\r\n            0x1b886a4c, 0xb81f2cc1, 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, 0x5a1d67b3, 0x52d2db92,\r\n            0x335610e9, 0x1347d66d, 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, 0xede51ce1,\r\n            0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,\r\n            0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839,\r\n            0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0};\r\n\r\n    private static final int[] Tinv1 = {0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1,\r\n            0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,\r\n            0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6,\r\n            0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, 0x89c2756a,\r\n            0x798ef478, 0x3e58996b, 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, 0x4adf6318, 0x311ae582,\r\n            0x33519760, 0x7f536245, 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, 0x6cde9487,\r\n            0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,\r\n            0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd,\r\n            0xbe0506d5, 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, 0xec830b39, 0xef6040aa,\r\n            0x9f715e06, 0x106ebd51, 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, 0x5dc47105, 0xd406046f,\r\n            0x155060ff, 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db,\r\n            0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb,\r\n            0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f,\r\n            0x96eeb4d2, 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, 0xba93e20a, 0x2aa0c0e5, 0xe0223c43,\r\n            0x171b121d, 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd,\r\n            0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, 0xdc31d7ca,\r\n            0x85634210, 0x22971340, 0x11c68420, 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,\r\n            0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8,\r\n            0x903322ef, 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4,\r\n            0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, 0x805d9fbe,\r\n            0x93d0697c, 0x2dd56fa9, 0x1225cfb3, 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, 0x18596ef4,\r\n            0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4,\r\n            0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315,\r\n            0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, 0xb5d19ee3,\r\n            0x886a4c1b, 0x1f2cc1b8, 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, 0x1d67b35a, 0xd2db9252,\r\n            0x5610e933, 0x47d66d13, 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, 0xe51ce1ed,\r\n            0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,\r\n            0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971,\r\n            0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042};\r\n\r\n    private static final int[] Tinv2 = {0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145,\r\n            0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,\r\n            0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9,\r\n            0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, 0xc2756a89,\r\n            0x8ef47879, 0x58996b3e, 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, 0xdf63184a, 0x1ae58231,\r\n            0x51976033, 0x5362457f, 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, 0xde94876c,\r\n            0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,\r\n            0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4,\r\n            0x0506d5be, 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, 0x830b39ec, 0x6040aaef,\r\n            0x715e069f, 0x6ebd5110, 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, 0xc471055d, 0x06046fd4,\r\n            0x5060ff15, 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee,\r\n            0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff,\r\n            0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7,\r\n            0xeeb4d296, 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, 0x93e20aba, 0xa0c0e52a, 0x223c43e0,\r\n            0x1b121d17, 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60,\r\n            0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, 0x31d7cadc,\r\n            0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,\r\n            0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c,\r\n            0x3322ef90, 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf,\r\n            0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, 0x5d9fbe80,\r\n            0xd0697c93, 0xd56fa92d, 0x25cfb312, 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, 0x596ef418,\r\n            0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409,\r\n            0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8,\r\n            0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, 0xd19ee3b5,\r\n            0x6a4c1b88, 0x2cc1b81f, 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, 0x67b35a1d, 0xdb9252d2,\r\n            0x10e93356, 0xd66d1347, 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, 0x1ce1ede5,\r\n            0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,\r\n            0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101,\r\n            0x0c08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257};\r\n\r\n    private static final int[] Tinv3 = {0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d,\r\n            0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,\r\n            0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3,\r\n            0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, 0x756a89c2,\r\n            0xf478798e, 0x996b3e58, 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, 0x63184adf, 0xe582311a,\r\n            0x97603351, 0x62457f53, 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, 0x94876cde,\r\n            0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,\r\n            0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da,\r\n            0x06d5be05, 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, 0x0b39ec83, 0x40aaef60,\r\n            0x5e069f71, 0xbd51106e, 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, 0x71055dc4, 0x046fd406,\r\n            0x60ff1550, 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8,\r\n            0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e,\r\n            0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757,\r\n            0xb4d296ee, 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, 0xe20aba93, 0xc0e52aa0, 0x3c43e022,\r\n            0x121d171b, 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f,\r\n            0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, 0xd7cadc31,\r\n            0x42108563, 0x13402297, 0x842011c6, 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,\r\n            0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d,\r\n            0x22ef9033, 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad,\r\n            0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, 0x9fbe805d,\r\n            0x697c93d0, 0x6fa92dd5, 0xcfb31225, 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, 0x6ef41859,\r\n            0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f,\r\n            0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7,\r\n            0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, 0x9ee3b5d1,\r\n            0x4c1b886a, 0xc1b81f2c, 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, 0xb35a1d67, 0x9252d2db,\r\n            0xe9335610, 0x6d1347d6, 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, 0xe1ede51c,\r\n            0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,\r\n            0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8,\r\n            0x08deb30c, 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8};\r\n    private static final int m1 = 0x80808080;\r\n\r\n\t/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */\r\n    private static final int m2 = 0x7f7f7f7f;\r\n    private static final int m3 = 0x0000001b;\r\n    private static final int BLOCK_SIZE = 16;\r\n    private int ROUNDS;\r\n\r\n\t/*\r\n     * The following defines provide alternative definitions of FFmulX that\r\n\t * might give improved performance if a fast 32-bit multiply is not\r\n\t * available.\r\n\t * \r\n\t * private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x &\r\n\t * m2) < < 1) ^ ((u >>> 3) | (u >>> 6)); } private static final int m4 =\r\n\t * 0x1b1b1b1b; private int FFmulX(int x) { int u = x & m1; return ((x & m2) < <\r\n\t * 1) ^ ((u - (u >>> 7)) & m4); }\r\n\t * \r\n\t */\r\n    private int[][] WorkingKey = null;\r\n    private int C0, C1, C2, C3;\r\n    private boolean doEncrypt;\r\n\r\n    /**\r\n     * default constructor - 128 bit block size.\r\n     */\r\n    public AES() {\r\n    }\r\n\r\n    private final int shift(int r, int shift) {\r\n        return (((r >>> shift) | (r << (32 - shift))));\r\n    }\r\n\r\n    private final int FFmulX(int x) {\r\n        return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));\r\n    }\r\n\r\n    private final int inv_mcol(int x) {\r\n        int f2 = FFmulX(x);\r\n        int f4 = FFmulX(f2);\r\n        int f8 = FFmulX(f4);\r\n        int f9 = x ^ f8;\r\n\r\n        return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24);\r\n    }\r\n\r\n    private final int subWord(int x) {\r\n        return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16) | S[(x >> 24) & 255] << 24);\r\n    }\r\n\r\n    /**\r\n     * Calculate the necessary round keys The number of calculations depends on\r\n     * key size and block size AES specified a fixed block size of 128 bits and\r\n     * key sizes 128/192/256 bits This code is written assuming those are the\r\n     * only possible values\r\n     */\r\n    private final int[][] generateWorkingKey(byte[] key, boolean forEncryption) {\r\n        int KC = key.length / 4; // key length in words\r\n        int t;\r\n\r\n        if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) {\r\n            throw new IllegalArgumentException(\"Key length not 128/192/256 bits.\");\r\n        }\r\n\r\n        ROUNDS = KC + 6; // This is not always true for the generalized\r\n        // Rijndael that allows larger block sizes\r\n        int[][] W = new int[ROUNDS + 1][4]; // 4 words in a block\r\n\r\n        //\r\n        // copy the key into the round key array\r\n        //\r\n\r\n        t = 0;\r\n        for (int i = 0; i < key.length; t++) {\r\n            W[t >> 2][t & 3] = (key[i] & 0xff) | ((key[i + 1] & 0xff) << 8) | ((key[i + 2] & 0xff) << 16)\r\n                    | (key[i + 3] << 24);\r\n            i += 4;\r\n        }\r\n\r\n        //\r\n        // while not enough round key material calculated\r\n        // calculate new values\r\n        //\r\n        int k = (ROUNDS + 1) << 2;\r\n        for (int i = KC; (i < k); i++) {\r\n            int temp = W[(i - 1) >> 2][(i - 1) & 3];\r\n            if ((i % KC) == 0) {\r\n                temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1];\r\n            } else if ((KC > 6) && ((i % KC) == 4)) {\r\n                temp = subWord(temp);\r\n            }\r\n\r\n            W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp;\r\n        }\r\n\r\n        if (!forEncryption) {\r\n            for (int j = 1; j < ROUNDS; j++) {\r\n                for (int i = 0; i < 4; i++) {\r\n                    W[j][i] = inv_mcol(W[j][i]);\r\n                }\r\n            }\r\n        }\r\n\r\n        return W;\r\n    }\r\n\r\n    /**\r\n     * initialise an AES cipher.\r\n     *\r\n     * @param forEncryption whether or not we are for encryption.\r\n     * @param key           the key required to set up the cipher.\r\n     * @throws IllegalArgumentException if the params argument is inappropriate.\r\n     */\r\n\r\n    public final void init(boolean forEncryption, byte[] key) {\r\n        WorkingKey = generateWorkingKey(key, forEncryption);\r\n        this.doEncrypt = forEncryption;\r\n    }\r\n\r\n    public final String getAlgorithmName() {\r\n        return \"AES\";\r\n    }\r\n\r\n    public final int getBlockSize() {\r\n        return BLOCK_SIZE;\r\n    }\r\n\r\n    public final int processBlock(byte[] in, int inOff, byte[] out, int outOff) {\r\n        if (WorkingKey == null) {\r\n            throw new IllegalStateException(\"AES engine not initialised\");\r\n        }\r\n\r\n        if ((inOff + (32 / 2)) > in.length) {\r\n            throw new IllegalArgumentException(\"input buffer too short\");\r\n        }\r\n\r\n        if ((outOff + (32 / 2)) > out.length) {\r\n            throw new IllegalArgumentException(\"output buffer too short\");\r\n        }\r\n\r\n        if (doEncrypt) {\r\n            unpackBlock(in, inOff);\r\n            encryptBlock(WorkingKey);\r\n            packBlock(out, outOff);\r\n        } else {\r\n            unpackBlock(in, inOff);\r\n            decryptBlock(WorkingKey);\r\n            packBlock(out, outOff);\r\n        }\r\n\r\n        return BLOCK_SIZE;\r\n    }\r\n\r\n    public final void reset() {\r\n    }\r\n\r\n    private final void unpackBlock(byte[] bytes, int off) {\r\n        int index = off;\r\n\r\n        C0 = (bytes[index++] & 0xff);\r\n        C0 |= (bytes[index++] & 0xff) << 8;\r\n        C0 |= (bytes[index++] & 0xff) << 16;\r\n        C0 |= bytes[index++] << 24;\r\n\r\n        C1 = (bytes[index++] & 0xff);\r\n        C1 |= (bytes[index++] & 0xff) << 8;\r\n        C1 |= (bytes[index++] & 0xff) << 16;\r\n        C1 |= bytes[index++] << 24;\r\n\r\n        C2 = (bytes[index++] & 0xff);\r\n        C2 |= (bytes[index++] & 0xff) << 8;\r\n        C2 |= (bytes[index++] & 0xff) << 16;\r\n        C2 |= bytes[index++] << 24;\r\n\r\n        C3 = (bytes[index++] & 0xff);\r\n        C3 |= (bytes[index++] & 0xff) << 8;\r\n        C3 |= (bytes[index++] & 0xff) << 16;\r\n        C3 |= bytes[index++] << 24;\r\n    }\r\n\r\n    private final void packBlock(byte[] bytes, int off) {\r\n        int index = off;\r\n\r\n        bytes[index++] = (byte) C0;\r\n        bytes[index++] = (byte) (C0 >> 8);\r\n        bytes[index++] = (byte) (C0 >> 16);\r\n        bytes[index++] = (byte) (C0 >> 24);\r\n\r\n        bytes[index++] = (byte) C1;\r\n        bytes[index++] = (byte) (C1 >> 8);\r\n        bytes[index++] = (byte) (C1 >> 16);\r\n        bytes[index++] = (byte) (C1 >> 24);\r\n\r\n        bytes[index++] = (byte) C2;\r\n        bytes[index++] = (byte) (C2 >> 8);\r\n        bytes[index++] = (byte) (C2 >> 16);\r\n        bytes[index++] = (byte) (C2 >> 24);\r\n\r\n        bytes[index++] = (byte) C3;\r\n        bytes[index++] = (byte) (C3 >> 8);\r\n        bytes[index++] = (byte) (C3 >> 16);\r\n        bytes[index++] = (byte) (C3 >> 24);\r\n    }\r\n\r\n    private final void encryptBlock(int[][] KW) {\r\n        int r, r0, r1, r2, r3;\r\n\r\n        C0 ^= KW[0][0];\r\n        C1 ^= KW[0][1];\r\n        C2 ^= KW[0][2];\r\n        C3 ^= KW[0][3];\r\n\r\n        for (r = 1; r < ROUNDS - 1; ) {\r\n            r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0];\r\n            r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1];\r\n            r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2];\r\n            r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3];\r\n            C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[(r3 >> 24) & 255] ^ KW[r][0];\r\n            C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[(r0 >> 24) & 255] ^ KW[r][1];\r\n            C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[(r1 >> 24) & 255] ^ KW[r][2];\r\n            C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[(r2 >> 24) & 255] ^ KW[r++][3];\r\n        }\r\n\r\n        r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0];\r\n        r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1];\r\n        r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2];\r\n        r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3];\r\n\r\n        // the final round's table is a simple function of S so we don't use a\r\n        // whole other four tables for it\r\n\r\n        C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16)\r\n                ^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0];\r\n        C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16)\r\n                ^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1];\r\n        C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16)\r\n                ^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2];\r\n        C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16)\r\n                ^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3];\r\n\r\n    }\r\n\r\n    private final void decryptBlock(int[][] KW) {\r\n        int r, r0, r1, r2, r3;\r\n\r\n        C0 ^= KW[ROUNDS][0];\r\n        C1 ^= KW[ROUNDS][1];\r\n        C2 ^= KW[ROUNDS][2];\r\n        C3 ^= KW[ROUNDS][3];\r\n\r\n        for (r = ROUNDS - 1; r > 1; ) {\r\n            r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255]\r\n                    ^ KW[r][0];\r\n            r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255]\r\n                    ^ KW[r][1];\r\n            r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255]\r\n                    ^ KW[r][2];\r\n            r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255]\r\n                    ^ KW[r--][3];\r\n            C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[(r1 >> 24) & 255]\r\n                    ^ KW[r][0];\r\n            C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[(r2 >> 24) & 255]\r\n                    ^ KW[r][1];\r\n            C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[(r3 >> 24) & 255]\r\n                    ^ KW[r][2];\r\n            C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[(r0 >> 24) & 255]\r\n                    ^ KW[r--][3];\r\n        }\r\n\r\n        r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255] ^ KW[r][0];\r\n        r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255] ^ KW[r][1];\r\n        r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255] ^ KW[r][2];\r\n        r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255] ^ KW[r--][3];\r\n\r\n        // the final round's table is a simple function of Si so we don't use a\r\n        // whole other four tables for it\r\n\r\n        C0 = (Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(r2 >> 16) & 255] & 255) << 16)\r\n                ^ (Si[(r1 >> 24) & 255] << 24) ^ KW[0][0];\r\n        C1 = (Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16)\r\n                ^ (Si[(r2 >> 24) & 255] << 24) ^ KW[0][1];\r\n        C2 = (Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8) ^ ((Si[(r0 >> 16) & 255] & 255) << 16)\r\n                ^ (Si[(r3 >> 24) & 255] << 24) ^ KW[0][2];\r\n        C3 = (Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8) ^ ((Si[(r1 >> 16) & 255] & 255) << 16)\r\n                ^ (Si[(r0 >> 24) & 255] << 24) ^ KW[0][3];\r\n    }\r\n\r\n    public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        processBlock(src, srcoff, dst, dstoff);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/BlockCipher.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/**\r\n * BlockCipher.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: BlockCipher.java,v 1.1 2005/05/26 14:53:27 cplattne Exp $\r\n */\r\npublic interface BlockCipher {\r\n    public void init(boolean forEncryption, byte[] key);\r\n\r\n    public int getBlockSize();\r\n\r\n    public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff);\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/BlockCipherFactory.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\nimport java.util.Vector;\r\n\r\n/**\r\n * BlockCipherFactory.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: BlockCipherFactory.java,v 1.4 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class BlockCipherFactory {\r\n    static Vector ciphers = new Vector();\r\n\r\n    static {\r\n        /* Higher Priority First */\r\n\r\n        ciphers.addElement(new CipherEntry(\"aes256-ctr\", 16, 32, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"aes192-ctr\", 16, 24, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"aes128-ctr\", 16, 16, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"blowfish-ctr\", 8, 16, \"ch.ethz.ssh2.crypto.cipher.BlowFish\"));\r\n\r\n        ciphers.addElement(new CipherEntry(\"aes256-cbc\", 16, 32, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"aes192-cbc\", 16, 24, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"aes128-cbc\", 16, 16, \"ch.ethz.ssh2.crypto.cipher.AES\"));\r\n        ciphers.addElement(new CipherEntry(\"blowfish-cbc\", 8, 16, \"ch.ethz.ssh2.crypto.cipher.BlowFish\"));\r\n\r\n        ciphers.addElement(new CipherEntry(\"3des-ctr\", 8, 24, \"ch.ethz.ssh2.crypto.cipher.DESede\"));\r\n        ciphers.addElement(new CipherEntry(\"3des-cbc\", 8, 24, \"ch.ethz.ssh2.crypto.cipher.DESede\"));\r\n    }\r\n\r\n    public static String[] getDefaultCipherList() {\r\n        String list[] = new String[ciphers.size()];\r\n        for (int i = 0; i < ciphers.size(); i++) {\r\n            CipherEntry ce = (CipherEntry) ciphers.elementAt(i);\r\n            list[i] = new String(ce.type);\r\n        }\r\n        return list;\r\n    }\r\n\r\n    public static void checkCipherList(String[] cipherCandidates) {\r\n        for (int i = 0; i < cipherCandidates.length; i++)\r\n            getEntry(cipherCandidates[i]);\r\n    }\r\n\r\n    public static BlockCipher createCipher(String type, boolean encrypt, byte[] key, byte[] iv) {\r\n        try {\r\n            CipherEntry ce = getEntry(type);\r\n            Class cc = Class.forName(ce.cipherClass);\r\n            BlockCipher bc = (BlockCipher) cc.newInstance();\r\n\r\n            if (type.endsWith(\"-cbc\")) {\r\n                bc.init(encrypt, key);\r\n                return new CBCMode(bc, iv, encrypt);\r\n            } else if (type.endsWith(\"-ctr\")) {\r\n                bc.init(true, key);\r\n                return new CTRMode(bc, iv, encrypt);\r\n            }\r\n            throw new IllegalArgumentException(\"Cannot instantiate \" + type);\r\n        } catch (Exception e) {\r\n            throw new IllegalArgumentException(\"Cannot instantiate \" + type);\r\n        }\r\n    }\r\n\r\n    private static CipherEntry getEntry(String type) {\r\n        for (int i = 0; i < ciphers.size(); i++) {\r\n            CipherEntry ce = (CipherEntry) ciphers.elementAt(i);\r\n            if (ce.type.equals(type))\r\n                return ce;\r\n        }\r\n        throw new IllegalArgumentException(\"Unkown algorithm \" + type);\r\n    }\r\n\r\n    public static int getBlockSize(String type) {\r\n        CipherEntry ce = getEntry(type);\r\n        return ce.blocksize;\r\n    }\r\n\r\n    public static int getKeySize(String type) {\r\n        CipherEntry ce = getEntry(type);\r\n        return ce.keysize;\r\n    }\r\n\r\n    static class CipherEntry {\r\n        String type;\r\n        int blocksize;\r\n        int keysize;\r\n        String cipherClass;\r\n\r\n        public CipherEntry(String type, int blockSize, int keySize, String cipherClass) {\r\n            this.type = type;\r\n            this.blocksize = blockSize;\r\n            this.keysize = keySize;\r\n            this.cipherClass = cipherClass;\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/BlowFish.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/*\r\n This file was shamelessly taken from the Bouncy Castle Crypto package.\r\n Their licence file states the following:\r\n\r\n Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle\r\n (http://www.bouncycastle.org)\r\n\r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n\r\n The above copyright notice and this permission notice shall be included in\r\n all copies or substantial portions of the Software.\r\n\r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n THE SOFTWARE. \r\n */\r\n\r\n/**\r\n * A class that provides Blowfish key encryption operations, such as encoding\r\n * data and generating keys. All the algorithms herein are from Applied\r\n * Cryptography and implement a simplified cryptography interface.\r\n *\r\n * @author See comments in the source file\r\n * @version $Id: BlowFish.java,v 1.3 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class BlowFish implements BlockCipher {\r\n\r\n    private final static int[] KP = {0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,\r\n            0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C, 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5,\r\n            0xB5470917, 0x9216D5D9, 0x8979FB1B},\r\n\r\n    KS0 = {0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99, 0x24A19947,\r\n            0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658,\r\n            0x718BCD58, 0x82154AEE, 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918,\r\n            0xB8DB38EF, 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,\r\n            0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE, 0xA15486AF,\r\n            0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C,\r\n            0x7A325381, 0x28958677, 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60,\r\n            0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,\r\n            0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2,\r\n            0xD8542F68, 0x960FA728, 0xAB5133A3, 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176,\r\n            0x66CA593E, 0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073, 0x401A449F,\r\n            0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,\r\n            0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7, 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6,\r\n            0x409F60C4, 0x5E5C9EC2, 0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C,\r\n            0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857, 0x45C8740F, 0xD20B5F39,\r\n            0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279, 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,\r\n            0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB,\r\n            0xCA6F8CA0, 0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0, 0xBBCA58C8,\r\n            0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B, 0x9A53E479, 0xB6F84565, 0xD28E49BC,\r\n            0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,\r\n            0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB,\r\n            0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD, 0x2F2F2218, 0xBE0E1777,\r\n            0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81,\r\n            0xD2ADA8D9, 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,\r\n            0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF, 0x2464369B,\r\n            0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5, 0x83260376, 0x6295CFA9,\r\n            0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476,\r\n            0x81E67400, 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,\r\n            0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A},\r\n\r\n    KS1 = {0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266, 0xECAA8C71,\r\n            0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65,\r\n            0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6,\r\n            0x021ECC5E, 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,\r\n            0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF, 0xAE0CF51A,\r\n            0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC,\r\n            0xC8B57634, 0x9AF3DDA7, 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1,\r\n            0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,\r\n            0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718,\r\n            0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C, 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908,\r\n            0xDD433B37, 0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55, 0x81AC77D6,\r\n            0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,\r\n            0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3, 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6,\r\n            0x5266C825, 0x2E4CC978, 0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D,\r\n            0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595, 0xA67BC883, 0xB17F37D1,\r\n            0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802, 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,\r\n            0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90,\r\n            0x4C70A239, 0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF, 0x19BDF0CA,\r\n            0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7, 0x9B540B19, 0x875FA099, 0x95F7997E,\r\n            0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,\r\n            0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF,\r\n            0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0, 0x45EEE2B6, 0xA3AAABEA,\r\n            0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A,\r\n            0x3D816250, 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,\r\n            0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061, 0x3372F092,\r\n            0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E, 0xA6078084, 0x19F8509E,\r\n            0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705,\r\n            0x0E1E9EC9, 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,\r\n            0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7},\r\n\r\n    KS2 = {0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068, 0xD4082471,\r\n            0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF,\r\n            0x70F4DDD3, 0x66A02F45, 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6,\r\n            0xABCA0A9A, 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,\r\n            0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42, 0x20FE9E35,\r\n            0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332,\r\n            0x6841E7F7, 0xCA7820FB, 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7,\r\n            0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,\r\n            0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE,\r\n            0x41041F0F, 0x404779A4, 0x5D886E17, 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60,\r\n            0xDFF8E8A3, 0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1, 0x3B240B62,\r\n            0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,\r\n            0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E, 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60,\r\n            0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3,\r\n            0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88, 0x515BAD24, 0x7B9479BF,\r\n            0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D, 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,\r\n            0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659,\r\n            0x0A121386, 0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057, 0xF0F7C086,\r\n            0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC, 0x83426B33, 0xF01EAB71, 0xB0804187,\r\n            0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,\r\n            0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E,\r\n            0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E, 0xB77F19B6, 0xE0A9DC09,\r\n            0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F,\r\n            0x2868F169, 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,\r\n            0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62, 0x11E69ED7,\r\n            0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76, 0x6F05E409, 0x4B7C0188,\r\n            0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3,\r\n            0x4DAD0FC4, 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,\r\n            0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0},\r\n\r\n    KS3 = {0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE, 0xD5118E9D,\r\n            0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79,\r\n            0xC6A376D2, 0x6549C2C8, 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8,\r\n            0xBE5EE304, 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,\r\n            0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9, 0xC72FEFD3,\r\n            0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797,\r\n            0x2CF0B7D9, 0x022B8B51, 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472,\r\n            0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,\r\n            0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15,\r\n            0x3C9057A2, 0x97271AEC, 0xA93A072A, 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5,\r\n            0x03563482, 0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E, 0x379D5862,\r\n            0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,\r\n            0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166, 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD,\r\n            0x1B588D40, 0xCCD2017F, 0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB,\r\n            0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D, 0xE75B1357, 0xF8721671,\r\n            0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84, 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,\r\n            0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1,\r\n            0x51CE794B, 0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749, 0xD44FBD9A,\r\n            0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F, 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF,\r\n            0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,\r\n            0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532,\r\n            0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8, 0xDF359F8D, 0x9B992F2E,\r\n            0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5,\r\n            0xF6FB2299, 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,\r\n            0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A, 0xC9AA53FD,\r\n            0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B, 0x53113EC0, 0x1640E3D3,\r\n            0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0,\r\n            0x4CF9AA7E, 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,\r\n            0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6};\r\n\r\n    // ====================================\r\n    // Useful constants\r\n    // ====================================\r\n\r\n    private static final int ROUNDS = 16;\r\n    private static final int BLOCK_SIZE = 8; // bytes = 64 bits\r\n    private static final int SBOX_SK = 256;\r\n    private static final int P_SZ = ROUNDS + 2;\r\n\r\n    private final int[] S0, S1, S2, S3; // the s-boxes\r\n    private final int[] P; // the p-array\r\n\r\n    private boolean doEncrypt = false;\r\n\r\n    private byte[] workingKey = null;\r\n\r\n    public BlowFish() {\r\n        S0 = new int[SBOX_SK];\r\n        S1 = new int[SBOX_SK];\r\n        S2 = new int[SBOX_SK];\r\n        S3 = new int[SBOX_SK];\r\n        P = new int[P_SZ];\r\n    }\r\n\r\n    /**\r\n     * initialise a Blowfish cipher.\r\n     *\r\n     * @param encrypting whether or not we are for encryption.\r\n     * @param key        the key required to set up the cipher.\r\n     * @throws IllegalArgumentException if the params argument is inappropriate.\r\n     */\r\n    public void init(boolean encrypting, byte[] key) {\r\n        this.doEncrypt = encrypting;\r\n        this.workingKey = key;\r\n        setKey(this.workingKey);\r\n    }\r\n\r\n    public String getAlgorithmName() {\r\n        return \"Blowfish\";\r\n    }\r\n\r\n    public final void transformBlock(byte[] in, int inOff, byte[] out, int outOff) {\r\n        if (workingKey == null) {\r\n            throw new IllegalStateException(\"Blowfish not initialised\");\r\n        }\r\n\r\n        if (doEncrypt) {\r\n            encryptBlock(in, inOff, out, outOff);\r\n        } else {\r\n            decryptBlock(in, inOff, out, outOff);\r\n        }\r\n    }\r\n\r\n    public void reset() {\r\n    }\r\n\r\n    public int getBlockSize() {\r\n        return BLOCK_SIZE;\r\n    }\r\n\r\n    // ==================================\r\n    // Private Implementation\r\n    // ==================================\r\n\r\n    private int F(int x) {\r\n        return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff]) ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);\r\n    }\r\n\r\n    /**\r\n     * apply the encryption cycle to each value pair in the table.\r\n     */\r\n    private void processTable(int xl, int xr, int[] table) {\r\n        int size = table.length;\r\n\r\n        for (int s = 0; s < size; s += 2) {\r\n            xl ^= P[0];\r\n\r\n            for (int i = 1; i < ROUNDS; i += 2) {\r\n                xr ^= F(xl) ^ P[i];\r\n                xl ^= F(xr) ^ P[i + 1];\r\n            }\r\n\r\n            xr ^= P[ROUNDS + 1];\r\n\r\n            table[s] = xr;\r\n            table[s + 1] = xl;\r\n\r\n            xr = xl; // end of cycle swap\r\n            xl = table[s];\r\n        }\r\n    }\r\n\r\n    private void setKey(byte[] key) {\r\n        /*\r\n\t\t * - comments are from _Applied Crypto_, Schneier, p338 please be\r\n\t\t * careful comparing the two, AC numbers the arrays from 1, the enclosed\r\n\t\t * code from 0.\r\n\t\t * \r\n\t\t * (1) Initialise the S-boxes and the P-array, with a fixed string This\r\n\t\t * string contains the hexadecimal digits of pi (3.141...)\r\n\t\t */\r\n        System.arraycopy(KS0, 0, S0, 0, SBOX_SK);\r\n        System.arraycopy(KS1, 0, S1, 0, SBOX_SK);\r\n        System.arraycopy(KS2, 0, S2, 0, SBOX_SK);\r\n        System.arraycopy(KS3, 0, S3, 0, SBOX_SK);\r\n\r\n        System.arraycopy(KP, 0, P, 0, P_SZ);\r\n\r\n\t\t/*\r\n\t\t * (2) Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with\r\n\t\t * the second 32-bits of the key, and so on for all bits of the key (up\r\n\t\t * to P[17]). Repeatedly cycle through the key bits until the entire\r\n\t\t * P-array has been XOR-ed with the key bits\r\n\t\t */\r\n        int keyLength = key.length;\r\n        int keyIndex = 0;\r\n\r\n        for (int i = 0; i < P_SZ; i++) {\r\n            // get the 32 bits of the key, in 4 * 8 bit chunks\r\n            int data = 0x0000000;\r\n            for (int j = 0; j < 4; j++) {\r\n                // create a 32 bit block\r\n                data = (data << 8) | (key[keyIndex++] & 0xff);\r\n\r\n                // wrap when we get to the end of the key\r\n                if (keyIndex >= keyLength) {\r\n                    keyIndex = 0;\r\n                }\r\n            }\r\n            // XOR the newly created 32 bit chunk onto the P-array\r\n            P[i] ^= data;\r\n        }\r\n\r\n\t\t/*\r\n\t\t * (3) Encrypt the all-zero string with the Blowfish algorithm, using\r\n\t\t * the subkeys described in (1) and (2)\r\n\t\t * \r\n\t\t * (4) Replace P1 and P2 with the output of step (3)\r\n\t\t * \r\n\t\t * (5) Encrypt the output of step(3) using the Blowfish algorithm, with\r\n\t\t * the modified subkeys.\r\n\t\t * \r\n\t\t * (6) Replace P3 and P4 with the output of step (5)\r\n\t\t * \r\n\t\t * (7) Continue the process, replacing all elements of the P-array and\r\n\t\t * then all four S-boxes in order, with the output of the continuously\r\n\t\t * changing Blowfish algorithm\r\n\t\t */\r\n\r\n        processTable(0, 0, P);\r\n        processTable(P[P_SZ - 2], P[P_SZ - 1], S0);\r\n        processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);\r\n        processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);\r\n        processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);\r\n    }\r\n\r\n    /**\r\n     * Encrypt the given input starting at the given offset and place the result\r\n     * in the provided buffer starting at the given offset. The input will be an\r\n     * exact multiple of our blocksize.\r\n     */\r\n    private void encryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex) {\r\n        int xl = BytesTo32bits(src, srcIndex);\r\n        int xr = BytesTo32bits(src, srcIndex + 4);\r\n\r\n        xl ^= P[0];\r\n\r\n        for (int i = 1; i < ROUNDS; i += 2) {\r\n            xr ^= F(xl) ^ P[i];\r\n            xl ^= F(xr) ^ P[i + 1];\r\n        }\r\n\r\n        xr ^= P[ROUNDS + 1];\r\n\r\n        Bits32ToBytes(xr, dst, dstIndex);\r\n        Bits32ToBytes(xl, dst, dstIndex + 4);\r\n    }\r\n\r\n    /**\r\n     * Decrypt the given input starting at the given offset and place the result\r\n     * in the provided buffer starting at the given offset. The input will be an\r\n     * exact multiple of our blocksize.\r\n     */\r\n    private void decryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex) {\r\n        int xl = BytesTo32bits(src, srcIndex);\r\n        int xr = BytesTo32bits(src, srcIndex + 4);\r\n\r\n        xl ^= P[ROUNDS + 1];\r\n\r\n        for (int i = ROUNDS; i > 0; i -= 2) {\r\n            xr ^= F(xl) ^ P[i];\r\n            xl ^= F(xr) ^ P[i - 1];\r\n        }\r\n\r\n        xr ^= P[0];\r\n\r\n        Bits32ToBytes(xr, dst, dstIndex);\r\n        Bits32ToBytes(xl, dst, dstIndex + 4);\r\n    }\r\n\r\n    private int BytesTo32bits(byte[] b, int i) {\r\n        return ((b[i] & 0xff) << 24) | ((b[i + 1] & 0xff) << 16) | ((b[i + 2] & 0xff) << 8) | ((b[i + 3] & 0xff));\r\n    }\r\n\r\n    private void Bits32ToBytes(int in, byte[] b, int offset) {\r\n        b[offset + 3] = (byte) in;\r\n        b[offset + 2] = (byte) (in >> 8);\r\n        b[offset + 1] = (byte) (in >> 16);\r\n        b[offset] = (byte) (in >> 24);\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/CBCMode.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/**\r\n * CBCMode.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: CBCMode.java,v 1.2 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class CBCMode implements BlockCipher {\r\n    BlockCipher tc;\r\n    int blockSize;\r\n    boolean doEncrypt;\r\n\r\n    byte[] cbc_vector;\r\n    byte[] tmp_vector;\r\n\r\n    public CBCMode(BlockCipher tc, byte[] iv, boolean doEncrypt)\r\n            throws IllegalArgumentException {\r\n        this.tc = tc;\r\n        this.blockSize = tc.getBlockSize();\r\n        this.doEncrypt = doEncrypt;\r\n\r\n        if (this.blockSize != iv.length)\r\n            throw new IllegalArgumentException(\"IV must be \" + blockSize\r\n                    + \" bytes long! (currently \" + iv.length + \")\");\r\n\r\n        this.cbc_vector = new byte[blockSize];\r\n        this.tmp_vector = new byte[blockSize];\r\n        System.arraycopy(iv, 0, cbc_vector, 0, blockSize);\r\n    }\r\n\r\n    public void init(boolean forEncryption, byte[] key) {\r\n    }\r\n\r\n    public int getBlockSize() {\r\n        return blockSize;\r\n    }\r\n\r\n    private void encryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        for (int i = 0; i < blockSize; i++)\r\n            cbc_vector[i] ^= src[srcoff + i];\r\n\r\n        tc.transformBlock(cbc_vector, 0, dst, dstoff);\r\n\r\n        System.arraycopy(dst, dstoff, cbc_vector, 0, blockSize);\r\n    }\r\n\r\n    private void decryptBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        /* Assume the worst, src and dst are overlapping... */\r\n\r\n        System.arraycopy(src, srcoff, tmp_vector, 0, blockSize);\r\n\r\n        tc.transformBlock(src, srcoff, dst, dstoff);\r\n\r\n        for (int i = 0; i < blockSize; i++)\r\n            dst[dstoff + i] ^= cbc_vector[i];\r\n\r\n\t\t/* ...that is why we need a tmp buffer. */\r\n\r\n        byte[] swap = cbc_vector;\r\n        cbc_vector = tmp_vector;\r\n        tmp_vector = swap;\r\n    }\r\n\r\n    public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        if (doEncrypt)\r\n            encryptBlock(src, srcoff, dst, dstoff);\r\n        else\r\n            decryptBlock(src, srcoff, dst, dstoff);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/CTRMode.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/**\r\n * This is CTR mode as described in draft-ietf-secsh-newmodes-XY.txt\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: CTRMode.java,v 1.1 2005/06/06 12:44:25 cplattne Exp $\r\n */\r\npublic class CTRMode implements BlockCipher {\r\n    byte[] X;\r\n    byte[] Xenc;\r\n\r\n    BlockCipher bc;\r\n    int blockSize;\r\n    boolean doEncrypt;\r\n\r\n    int count = 0;\r\n\r\n    public CTRMode(BlockCipher tc, byte[] iv, boolean doEnc) throws IllegalArgumentException {\r\n        bc = tc;\r\n        blockSize = bc.getBlockSize();\r\n        doEncrypt = doEnc;\r\n\r\n        if (blockSize != iv.length)\r\n            throw new IllegalArgumentException(\"IV must be \" + blockSize + \" bytes long! (currently \" + iv.length + \")\");\r\n\r\n        X = new byte[blockSize];\r\n        Xenc = new byte[blockSize];\r\n\r\n        System.arraycopy(iv, 0, X, 0, blockSize);\r\n    }\r\n\r\n    public void init(boolean forEncryption, byte[] key) {\r\n    }\r\n\r\n    public final int getBlockSize() {\r\n        return blockSize;\r\n    }\r\n\r\n    public final void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        bc.transformBlock(X, 0, Xenc, 0);\r\n\r\n        for (int i = 0; i < blockSize; i++) {\r\n            dst[dstoff + i] = (byte) (src[srcoff + i] ^ Xenc[i]);\r\n        }\r\n\r\n        for (int i = (blockSize - 1); i >= 0; i--) {\r\n            X[i]++;\r\n            if (X[i] != 0)\r\n                break;\r\n\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/CipherInputStream.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\n\r\n/**\r\n * CipherInputStream.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: CipherInputStream.java,v 1.3 2006/02/14 15:17:37 cplattne Exp $\r\n */\r\npublic class CipherInputStream {\r\n    final int BUFF_SIZE = 2048;\r\n    BlockCipher currentCipher;\r\n    InputStream bi;\r\n    byte[] buffer;\r\n    byte[] enc;\r\n    int blockSize;\r\n\r\n\t/*\r\n     * We cannot use java.io.BufferedInputStream, since that is not available in\r\n\t * J2ME. Everything could be improved alot here.\r\n\t */\r\n    int pos;\r\n    byte[] input_buffer = new byte[BUFF_SIZE];\r\n    int input_buffer_pos = 0;\r\n    int input_buffer_size = 0;\r\n\r\n    public CipherInputStream(BlockCipher tc, InputStream bi) {\r\n        this.bi = bi;\r\n        changeCipher(tc);\r\n    }\r\n\r\n    private int fill_buffer() throws IOException {\r\n        input_buffer_pos = 0;\r\n        input_buffer_size = bi.read(input_buffer, 0, BUFF_SIZE);\r\n        return input_buffer_size;\r\n    }\r\n\r\n    private int internal_read(byte[] b, int off, int len) throws IOException {\r\n        if (input_buffer_size < 0)\r\n            return -1;\r\n\r\n        if (input_buffer_pos >= input_buffer_size) {\r\n            if (fill_buffer() <= 0)\r\n                return -1;\r\n        }\r\n\r\n        int avail = input_buffer_size - input_buffer_pos;\r\n        int thiscopy = (len > avail) ? avail : len;\r\n\r\n        System.arraycopy(input_buffer, input_buffer_pos, b, off, thiscopy);\r\n        input_buffer_pos += thiscopy;\r\n\r\n        return thiscopy;\r\n    }\r\n\r\n    public void changeCipher(BlockCipher bc) {\r\n        this.currentCipher = bc;\r\n        blockSize = bc.getBlockSize();\r\n        buffer = new byte[blockSize];\r\n        enc = new byte[blockSize];\r\n        pos = blockSize;\r\n    }\r\n\r\n    private void getBlock() throws IOException {\r\n        int n = 0;\r\n        while (n < blockSize) {\r\n            int len = internal_read(enc, n, blockSize - n);\r\n            if (len < 0)\r\n                throw new IOException(\"Cannot read full block, EOF reached.\");\r\n            n += len;\r\n        }\r\n\r\n        try {\r\n            currentCipher.transformBlock(enc, 0, buffer, 0);\r\n        } catch (Exception e) {\r\n            throw new IOException(\"Error while decrypting block.\");\r\n        }\r\n        pos = 0;\r\n    }\r\n\r\n    public int read(byte[] dst) throws IOException {\r\n        return read(dst, 0, dst.length);\r\n    }\r\n\r\n    public int read(byte[] dst, int off, int len) throws IOException {\r\n        int count = 0;\r\n\r\n        while (len > 0) {\r\n            if (pos >= blockSize)\r\n                getBlock();\r\n\r\n            int avail = blockSize - pos;\r\n            int copy = Math.min(avail, len);\r\n            System.arraycopy(buffer, pos, dst, off, copy);\r\n            pos += copy;\r\n            off += copy;\r\n            len -= copy;\r\n            count += copy;\r\n        }\r\n        return count;\r\n    }\r\n\r\n    public int read() throws IOException {\r\n        if (pos >= blockSize) {\r\n            getBlock();\r\n        }\r\n        return buffer[pos++] & 0xff;\r\n    }\r\n\r\n    public int readPlain(byte[] b, int off, int len) throws IOException {\r\n        if (pos != blockSize)\r\n            throw new IOException(\"Cannot read plain since crypto buffer is not aligned.\");\r\n        int n = 0;\r\n        while (n < len) {\r\n            int cnt = internal_read(b, off + n, len - n);\r\n            if (cnt < 0)\r\n                throw new IOException(\"Cannot fill buffer, EOF reached.\");\r\n            n += cnt;\r\n        }\r\n        return n;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/CipherOutputStream.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\nimport java.io.IOException;\r\nimport java.io.OutputStream;\r\n\r\n/**\r\n * CipherOutputStream.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: CipherOutputStream.java,v 1.4 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class CipherOutputStream {\r\n    final int BUFF_SIZE = 2048;\r\n    BlockCipher currentCipher;\r\n    OutputStream bo;\r\n    byte[] buffer;\r\n    byte[] enc;\r\n    int blockSize;\r\n\r\n\t/*\r\n     * We cannot use java.io.BufferedOutputStream, since that is not available\r\n\t * in J2ME. Everything could be improved here alot.\r\n\t */\r\n    int pos;\r\n    byte[] out_buffer = new byte[BUFF_SIZE];\r\n    int out_buffer_pos = 0;\r\n\r\n    public CipherOutputStream(BlockCipher tc, OutputStream bo) {\r\n        this.bo = bo;\r\n        changeCipher(tc);\r\n    }\r\n\r\n    private void internal_write(byte[] src, int off, int len) throws IOException {\r\n        while (len > 0) {\r\n            int space = BUFF_SIZE - out_buffer_pos;\r\n            int copy = (len > space) ? space : len;\r\n\r\n            System.arraycopy(src, off, out_buffer, out_buffer_pos, copy);\r\n\r\n            off += copy;\r\n            out_buffer_pos += copy;\r\n            len -= copy;\r\n\r\n            if (out_buffer_pos >= BUFF_SIZE) {\r\n                bo.write(out_buffer, 0, BUFF_SIZE);\r\n                out_buffer_pos = 0;\r\n            }\r\n        }\r\n    }\r\n\r\n    private void internal_write(int b) throws IOException {\r\n        out_buffer[out_buffer_pos++] = (byte) b;\r\n        if (out_buffer_pos >= BUFF_SIZE) {\r\n            bo.write(out_buffer, 0, BUFF_SIZE);\r\n            out_buffer_pos = 0;\r\n        }\r\n    }\r\n\r\n    public void flush() throws IOException {\r\n        if (pos != 0)\r\n            throw new IOException(\"FATAL: cannot flush since crypto buffer is not aligned.\");\r\n\r\n        if (out_buffer_pos > 0) {\r\n            bo.write(out_buffer, 0, out_buffer_pos);\r\n            out_buffer_pos = 0;\r\n        }\r\n        bo.flush();\r\n    }\r\n\r\n    public void changeCipher(BlockCipher bc) {\r\n        this.currentCipher = bc;\r\n        blockSize = bc.getBlockSize();\r\n        buffer = new byte[blockSize];\r\n        enc = new byte[blockSize];\r\n        pos = 0;\r\n    }\r\n\r\n    private void writeBlock() throws IOException {\r\n        try {\r\n            currentCipher.transformBlock(buffer, 0, enc, 0);\r\n        } catch (Exception e) {\r\n            throw (IOException) new IOException(\"Error while decrypting block.\").initCause(e);\r\n        }\r\n\r\n        internal_write(enc, 0, blockSize);\r\n        pos = 0;\r\n    }\r\n\r\n    public void write(byte[] src, int off, int len) throws IOException {\r\n        while (len > 0) {\r\n            int avail = blockSize - pos;\r\n            int copy = Math.min(avail, len);\r\n\r\n            System.arraycopy(src, off, buffer, pos, copy);\r\n            pos += copy;\r\n            off += copy;\r\n            len -= copy;\r\n\r\n            if (pos >= blockSize)\r\n                writeBlock();\r\n        }\r\n    }\r\n\r\n    public void write(int b) throws IOException {\r\n        buffer[pos++] = (byte) b;\r\n        if (pos >= blockSize)\r\n            writeBlock();\r\n    }\r\n\r\n    public void writePlain(int b) throws IOException {\r\n        if (pos != 0)\r\n            throw new IOException(\"Cannot write plain since crypto buffer is not aligned.\");\r\n        internal_write(b);\r\n    }\r\n\r\n    public void writePlain(byte[] b, int off, int len) throws IOException {\r\n        if (pos != 0)\r\n            throw new IOException(\"Cannot write plain since crypto buffer is not aligned.\");\r\n        internal_write(b, off, len);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/DES.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/*\r\n This file is based on the 3DES implementation from the Bouncy Castle Crypto package.\r\n Their licence file states the following:\r\n\r\n Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle\r\n (http://www.bouncycastle.org)\r\n\r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n\r\n The above copyright notice and this permission notice shall be included in\r\n all copies or substantial portions of the Software.\r\n\r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n THE SOFTWARE. \r\n */\r\n\r\n/**\r\n * DES.\r\n *\r\n * @author See comments in the source file\r\n * @version $Id: DES.java,v 1.3 2005/12/05 17:13:27 cplattne Exp $ethz.ch\r\n */\r\npublic class DES implements BlockCipher {\r\n    /**\r\n     * what follows is mainly taken from \"Applied Cryptography\", by Bruce\r\n     * Schneier, however it also bears great resemblance to Richard\r\n     * Outerbridge's D3DES...\r\n     */\r\n\r\n    static short[] Df_Key = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,\r\n            0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67};\r\n    static short[] bytebit = {0200, 0100, 040, 020, 010, 04, 02, 01};\r\n    static int[] bigbyte = {0x800000, 0x400000, 0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000,\r\n            0x4000, 0x2000, 0x1000, 0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};\r\n    static byte[] pc1 = {56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2,\r\n            59, 51, 43, 35, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 60, 52, 44, 36, 28, 20, 12,\r\n            4, 27, 19, 11, 3};\r\n    static byte[] totrot = {1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28};\r\n    static byte[] pc2 = {13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, 40,\r\n            51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31};\r\n    static int[] SP1 = {0x01010400, 0x00000000, 0x00010000, 0x01010404, 0x01010004, 0x00010404, 0x00000004,\r\n            0x00010000, 0x00000400, 0x01010400, 0x01010404, 0x00000400, 0x01000404, 0x01010004, 0x01000000, 0x00000004,\r\n            0x00000404, 0x01000400, 0x01000400, 0x00010400, 0x00010400, 0x01010000, 0x01010000, 0x01000404, 0x00010004,\r\n            0x01000004, 0x01000004, 0x00010004, 0x00000000, 0x00000404, 0x00010404, 0x01000000, 0x00010000, 0x01010404,\r\n            0x00000004, 0x01010000, 0x01010400, 0x01000000, 0x01000000, 0x00000400, 0x01010004, 0x00010000, 0x00010400,\r\n            0x01000004, 0x00000400, 0x00000004, 0x01000404, 0x00010404, 0x01010404, 0x00010004, 0x01010000, 0x01000404,\r\n            0x01000004, 0x00000404, 0x00010404, 0x01010400, 0x00000404, 0x01000400, 0x01000400, 0x00000000, 0x00010004,\r\n            0x00010400, 0x00000000, 0x01010004};\r\n    static int[] SP2 = {0x80108020, 0x80008000, 0x00008000, 0x00108020, 0x00100000, 0x00000020, 0x80100020,\r\n            0x80008020, 0x80000020, 0x80108020, 0x80108000, 0x80000000, 0x80008000, 0x00100000, 0x00000020, 0x80100020,\r\n            0x00108000, 0x00100020, 0x80008020, 0x00000000, 0x80000000, 0x00008000, 0x00108020, 0x80100000, 0x00100020,\r\n            0x80000020, 0x00000000, 0x00108000, 0x00008020, 0x80108000, 0x80100000, 0x00008020, 0x00000000, 0x00108020,\r\n            0x80100020, 0x00100000, 0x80008020, 0x80100000, 0x80108000, 0x00008000, 0x80100000, 0x80008000, 0x00000020,\r\n            0x80108020, 0x00108020, 0x00000020, 0x00008000, 0x80000000, 0x00008020, 0x80108000, 0x00100000, 0x80000020,\r\n            0x00100020, 0x80008020, 0x80000020, 0x00100020, 0x00108000, 0x00000000, 0x80008000, 0x00008020, 0x80000000,\r\n            0x80100020, 0x80108020, 0x00108000};\r\n    static int[] SP3 = {0x00000208, 0x08020200, 0x00000000, 0x08020008, 0x08000200, 0x00000000, 0x00020208,\r\n            0x08000200, 0x00020008, 0x08000008, 0x08000008, 0x00020000, 0x08020208, 0x00020008, 0x08020000, 0x00000208,\r\n            0x08000000, 0x00000008, 0x08020200, 0x00000200, 0x00020200, 0x08020000, 0x08020008, 0x00020208, 0x08000208,\r\n            0x00020200, 0x00020000, 0x08000208, 0x00000008, 0x08020208, 0x00000200, 0x08000000, 0x08020200, 0x08000000,\r\n            0x00020008, 0x00000208, 0x00020000, 0x08020200, 0x08000200, 0x00000000, 0x00000200, 0x00020008, 0x08020208,\r\n            0x08000200, 0x08000008, 0x00000200, 0x00000000, 0x08020008, 0x08000208, 0x00020000, 0x08000000, 0x08020208,\r\n            0x00000008, 0x00020208, 0x00020200, 0x08000008, 0x08020000, 0x08000208, 0x00000208, 0x08020000, 0x00020208,\r\n            0x00000008, 0x08020008, 0x00020200};\r\n    static int[] SP4 = {0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802080, 0x00800081, 0x00800001,\r\n            0x00002001, 0x00000000, 0x00802000, 0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00800080, 0x00800001,\r\n            0x00000001, 0x00002000, 0x00800000, 0x00802001, 0x00000080, 0x00800000, 0x00002001, 0x00002080, 0x00800081,\r\n            0x00000001, 0x00002080, 0x00800080, 0x00002000, 0x00802080, 0x00802081, 0x00000081, 0x00800080, 0x00800001,\r\n            0x00802000, 0x00802081, 0x00000081, 0x00000000, 0x00000000, 0x00802000, 0x00002080, 0x00800080, 0x00800081,\r\n            0x00000001, 0x00802001, 0x00002081, 0x00002081, 0x00000080, 0x00802081, 0x00000081, 0x00000001, 0x00002000,\r\n            0x00800001, 0x00002001, 0x00802080, 0x00800081, 0x00002001, 0x00002080, 0x00800000, 0x00802001, 0x00000080,\r\n            0x00800000, 0x00002000, 0x00802080};\r\n\r\n\t/*\r\n     * Use the key schedule specified in the Standard (ANSI X3.92-1981).\r\n\t */\r\n    static int[] SP5 = {0x00000100, 0x02080100, 0x02080000, 0x42000100, 0x00080000, 0x00000100, 0x40000000,\r\n            0x02080000, 0x40080100, 0x00080000, 0x02000100, 0x40080100, 0x42000100, 0x42080000, 0x00080100, 0x40000000,\r\n            0x02000000, 0x40080000, 0x40080000, 0x00000000, 0x40000100, 0x42080100, 0x42080100, 0x02000100, 0x42080000,\r\n            0x40000100, 0x00000000, 0x42000000, 0x02080100, 0x02000000, 0x42000000, 0x00080100, 0x00080000, 0x42000100,\r\n            0x00000100, 0x02000000, 0x40000000, 0x02080000, 0x42000100, 0x40080100, 0x02000100, 0x40000000, 0x42080000,\r\n            0x02080100, 0x40080100, 0x00000100, 0x02000000, 0x42080000, 0x42080100, 0x00080100, 0x42000000, 0x42080100,\r\n            0x02080000, 0x00000000, 0x40080000, 0x42000000, 0x00080100, 0x02000100, 0x40000100, 0x00080000, 0x00000000,\r\n            0x40080000, 0x02080100, 0x40000100};\r\n    static int[] SP6 = {0x20000010, 0x20400000, 0x00004000, 0x20404010, 0x20400000, 0x00000010, 0x20404010,\r\n            0x00400000, 0x20004000, 0x00404010, 0x00400000, 0x20000010, 0x00400010, 0x20004000, 0x20000000, 0x00004010,\r\n            0x00000000, 0x00400010, 0x20004010, 0x00004000, 0x00404000, 0x20004010, 0x00000010, 0x20400010, 0x20400010,\r\n            0x00000000, 0x00404010, 0x20404000, 0x00004010, 0x00404000, 0x20404000, 0x20000000, 0x20004000, 0x00000010,\r\n            0x20400010, 0x00404000, 0x20404010, 0x00400000, 0x00004010, 0x20000010, 0x00400000, 0x20004000, 0x20000000,\r\n            0x00004010, 0x20000010, 0x20404010, 0x00404000, 0x20400000, 0x00404010, 0x20404000, 0x00000000, 0x20400010,\r\n            0x00000010, 0x00004000, 0x20400000, 0x00404010, 0x00004000, 0x00400010, 0x20004010, 0x00000000, 0x20404000,\r\n            0x20000000, 0x00400010, 0x20004010};\r\n    static int[] SP7 = {0x00200000, 0x04200002, 0x04000802, 0x00000000, 0x00000800, 0x04000802, 0x00200802,\r\n            0x04200800, 0x04200802, 0x00200000, 0x00000000, 0x04000002, 0x00000002, 0x04000000, 0x04200002, 0x00000802,\r\n            0x04000800, 0x00200802, 0x00200002, 0x04000800, 0x04000002, 0x04200000, 0x04200800, 0x00200002, 0x04200000,\r\n            0x00000800, 0x00000802, 0x04200802, 0x00200800, 0x00000002, 0x04000000, 0x00200800, 0x04000000, 0x00200800,\r\n            0x00200000, 0x04000802, 0x04000802, 0x04200002, 0x04200002, 0x00000002, 0x00200002, 0x04000000, 0x04000800,\r\n            0x00200000, 0x04200800, 0x00000802, 0x00200802, 0x04200800, 0x00000802, 0x04000002, 0x04200802, 0x04200000,\r\n            0x00200800, 0x00000000, 0x00000002, 0x04200802, 0x00000000, 0x00200802, 0x04200000, 0x00000800, 0x04000002,\r\n            0x04000800, 0x00000800, 0x00200002};\r\n    static int[] SP8 = {0x10001040, 0x00001000, 0x00040000, 0x10041040, 0x10000000, 0x10001040, 0x00000040,\r\n            0x10000000, 0x00040040, 0x10040000, 0x10041040, 0x00041000, 0x10041000, 0x00041040, 0x00001000, 0x00000040,\r\n            0x10040000, 0x10000040, 0x10001000, 0x00001040, 0x00041000, 0x00040040, 0x10040040, 0x10041000, 0x00001040,\r\n            0x00000000, 0x00000000, 0x10040040, 0x10000040, 0x10001000, 0x00041040, 0x00040000, 0x00041040, 0x00040000,\r\n            0x10041000, 0x00001000, 0x00000040, 0x10040040, 0x00001000, 0x00041040, 0x10001000, 0x00000040, 0x10000040,\r\n            0x10040000, 0x10040040, 0x10000000, 0x00040000, 0x10001040, 0x00000000, 0x10041040, 0x00040040, 0x10000040,\r\n            0x10040000, 0x10001000, 0x10001040, 0x00000000, 0x10041040, 0x00041000, 0x00041000, 0x00001040, 0x00001040,\r\n            0x00040040, 0x10000000, 0x10041000};\r\n    private int[] workingKey = null;\r\n\r\n    /**\r\n     * standard constructor.\r\n     */\r\n    public DES() {\r\n    }\r\n\r\n    /**\r\n     * initialise a DES cipher.\r\n     *\r\n     * @param encrypting whether or not we are for encryption.\r\n     * @param key        the parameters required to set up the cipher.\r\n     * @throws IllegalArgumentException if the params argument is inappropriate.\r\n     */\r\n    public void init(boolean encrypting, byte[] key) {\r\n        this.workingKey = generateWorkingKey(encrypting, key, 0);\r\n    }\r\n\r\n    public String getAlgorithmName() {\r\n        return \"DES\";\r\n    }\r\n\r\n    public int getBlockSize() {\r\n        return 8;\r\n    }\r\n\r\n    public void transformBlock(byte[] in, int inOff, byte[] out, int outOff) {\r\n        if (workingKey == null) {\r\n            throw new IllegalStateException(\"DES engine not initialised!\");\r\n        }\r\n\r\n        desFunc(workingKey, in, inOff, out, outOff);\r\n    }\r\n\r\n    public void reset() {\r\n    }\r\n\r\n    /**\r\n     * generate an integer based working key based on our secret key and what we\r\n     * processing we are planning to do.\r\n     * <p>\r\n     * Acknowledgements for this routine go to James Gillogly & Phil Karn.\r\n     * (whoever, and wherever they are!).\r\n     */\r\n    protected int[] generateWorkingKey(boolean encrypting, byte[] key, int off) {\r\n        int[] newKey = new int[32];\r\n        boolean[] pc1m = new boolean[56], pcr = new boolean[56];\r\n\r\n        for (int j = 0; j < 56; j++) {\r\n            int l = pc1[j];\r\n\r\n            pc1m[j] = ((key[off + (l >>> 3)] & bytebit[l & 07]) != 0);\r\n        }\r\n\r\n        for (int i = 0; i < 16; i++) {\r\n            int l, m, n;\r\n\r\n            if (encrypting) {\r\n                m = i << 1;\r\n            } else {\r\n                m = (15 - i) << 1;\r\n            }\r\n\r\n            n = m + 1;\r\n            newKey[m] = newKey[n] = 0;\r\n\r\n            for (int j = 0; j < 28; j++) {\r\n                l = j + totrot[i];\r\n                if (l < 28) {\r\n                    pcr[j] = pc1m[l];\r\n                } else {\r\n                    pcr[j] = pc1m[l - 28];\r\n                }\r\n            }\r\n\r\n            for (int j = 28; j < 56; j++) {\r\n                l = j + totrot[i];\r\n                if (l < 56) {\r\n                    pcr[j] = pc1m[l];\r\n                } else {\r\n                    pcr[j] = pc1m[l - 28];\r\n                }\r\n            }\r\n\r\n            for (int j = 0; j < 24; j++) {\r\n                if (pcr[pc2[j]]) {\r\n                    newKey[m] |= bigbyte[j];\r\n                }\r\n\r\n                if (pcr[pc2[j + 24]]) {\r\n                    newKey[n] |= bigbyte[j];\r\n                }\r\n            }\r\n        }\r\n\r\n        //\r\n        // store the processed key\r\n        //\r\n        for (int i = 0; i != 32; i += 2) {\r\n            int i1, i2;\r\n\r\n            i1 = newKey[i];\r\n            i2 = newKey[i + 1];\r\n\r\n            newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10) | ((i2 & 0x00fc0000) >>> 10)\r\n                    | ((i2 & 0x00000fc0) >>> 6);\r\n\r\n            newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16) | ((i2 & 0x0003f000) >>> 4)\r\n                    | (i2 & 0x0000003f);\r\n        }\r\n\r\n        return newKey;\r\n    }\r\n\r\n    /**\r\n     * the DES engine.\r\n     */\r\n    protected void desFunc(int[] wKey, byte[] in, int inOff, byte[] out, int outOff) {\r\n        int work, right, left;\r\n\r\n        left = (in[inOff + 0] & 0xff) << 24;\r\n        left |= (in[inOff + 1] & 0xff) << 16;\r\n        left |= (in[inOff + 2] & 0xff) << 8;\r\n        left |= (in[inOff + 3] & 0xff);\r\n\r\n        right = (in[inOff + 4] & 0xff) << 24;\r\n        right |= (in[inOff + 5] & 0xff) << 16;\r\n        right |= (in[inOff + 6] & 0xff) << 8;\r\n        right |= (in[inOff + 7] & 0xff);\r\n\r\n        work = ((left >>> 4) ^ right) & 0x0f0f0f0f;\r\n        right ^= work;\r\n        left ^= (work << 4);\r\n        work = ((left >>> 16) ^ right) & 0x0000ffff;\r\n        right ^= work;\r\n        left ^= (work << 16);\r\n        work = ((right >>> 2) ^ left) & 0x33333333;\r\n        left ^= work;\r\n        right ^= (work << 2);\r\n        work = ((right >>> 8) ^ left) & 0x00ff00ff;\r\n        left ^= work;\r\n        right ^= (work << 8);\r\n        right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;\r\n        work = (left ^ right) & 0xaaaaaaaa;\r\n        left ^= work;\r\n        right ^= work;\r\n        left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;\r\n\r\n        for (int round = 0; round < 8; round++) {\r\n            int fval;\r\n\r\n            work = (right << 28) | (right >>> 4);\r\n            work ^= wKey[round * 4 + 0];\r\n            fval = SP7[work & 0x3f];\r\n            fval |= SP5[(work >>> 8) & 0x3f];\r\n            fval |= SP3[(work >>> 16) & 0x3f];\r\n            fval |= SP1[(work >>> 24) & 0x3f];\r\n            work = right ^ wKey[round * 4 + 1];\r\n            fval |= SP8[work & 0x3f];\r\n            fval |= SP6[(work >>> 8) & 0x3f];\r\n            fval |= SP4[(work >>> 16) & 0x3f];\r\n            fval |= SP2[(work >>> 24) & 0x3f];\r\n            left ^= fval;\r\n            work = (left << 28) | (left >>> 4);\r\n            work ^= wKey[round * 4 + 2];\r\n            fval = SP7[work & 0x3f];\r\n            fval |= SP5[(work >>> 8) & 0x3f];\r\n            fval |= SP3[(work >>> 16) & 0x3f];\r\n            fval |= SP1[(work >>> 24) & 0x3f];\r\n            work = left ^ wKey[round * 4 + 3];\r\n            fval |= SP8[work & 0x3f];\r\n            fval |= SP6[(work >>> 8) & 0x3f];\r\n            fval |= SP4[(work >>> 16) & 0x3f];\r\n            fval |= SP2[(work >>> 24) & 0x3f];\r\n            right ^= fval;\r\n        }\r\n\r\n        right = (right << 31) | (right >>> 1);\r\n        work = (left ^ right) & 0xaaaaaaaa;\r\n        left ^= work;\r\n        right ^= work;\r\n        left = (left << 31) | (left >>> 1);\r\n        work = ((left >>> 8) ^ right) & 0x00ff00ff;\r\n        right ^= work;\r\n        left ^= (work << 8);\r\n        work = ((left >>> 2) ^ right) & 0x33333333;\r\n        right ^= work;\r\n        left ^= (work << 2);\r\n        work = ((right >>> 16) ^ left) & 0x0000ffff;\r\n        left ^= work;\r\n        right ^= (work << 16);\r\n        work = ((right >>> 4) ^ left) & 0x0f0f0f0f;\r\n        left ^= work;\r\n        right ^= (work << 4);\r\n\r\n        out[outOff + 0] = (byte) ((right >>> 24) & 0xff);\r\n        out[outOff + 1] = (byte) ((right >>> 16) & 0xff);\r\n        out[outOff + 2] = (byte) ((right >>> 8) & 0xff);\r\n        out[outOff + 3] = (byte) (right & 0xff);\r\n        out[outOff + 4] = (byte) ((left >>> 24) & 0xff);\r\n        out[outOff + 5] = (byte) ((left >>> 16) & 0xff);\r\n        out[outOff + 6] = (byte) ((left >>> 8) & 0xff);\r\n        out[outOff + 7] = (byte) (left & 0xff);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/DESede.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/*\r\n This file was shamelessly taken (and modified) from the Bouncy Castle Crypto package.\r\n Their licence file states the following:\r\n\r\n Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle\r\n (http://www.bouncycastle.org)\r\n\r\n Permission is hereby granted, free of charge, to any person obtaining a copy\r\n of this software and associated documentation files (the \"Software\"), to deal\r\n in the Software without restriction, including without limitation the rights\r\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n copies of the Software, and to permit persons to whom the Software is\r\n furnished to do so, subject to the following conditions:\r\n\r\n The above copyright notice and this permission notice shall be included in\r\n all copies or substantial portions of the Software.\r\n\r\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n THE SOFTWARE. \r\n */\r\n\r\n/**\r\n * DESede.\r\n *\r\n * @author See comments in the source file\r\n * @version $Id: DESede.java,v 1.3 2005/08/11 12:47:27 cplattne Exp $ethz.ch\r\n */\r\npublic class DESede extends DES {\r\n    private int[] key1 = null;\r\n    private int[] key2 = null;\r\n    private int[] key3 = null;\r\n\r\n    private boolean encrypt;\r\n\r\n    /**\r\n     * standard constructor.\r\n     */\r\n    public DESede() {\r\n    }\r\n\r\n    /**\r\n     * initialise a DES cipher.\r\n     *\r\n     * @param encrypting whether or not we are for encryption.\r\n     * @param key        the parameters required to set up the cipher.\r\n     * @throws IllegalArgumentException if the params argument is inappropriate.\r\n     */\r\n    public void init(boolean encrypting, byte[] key) {\r\n        key1 = generateWorkingKey(encrypting, key, 0);\r\n        key2 = generateWorkingKey(!encrypting, key, 8);\r\n        key3 = generateWorkingKey(encrypting, key, 16);\r\n\r\n        encrypt = encrypting;\r\n    }\r\n\r\n    public String getAlgorithmName() {\r\n        return \"DESede\";\r\n    }\r\n\r\n    public int getBlockSize() {\r\n        return 8;\r\n    }\r\n\r\n    public void transformBlock(byte[] in, int inOff, byte[] out, int outOff) {\r\n        if (key1 == null) {\r\n            throw new IllegalStateException(\"DESede engine not initialised!\");\r\n        }\r\n\r\n        if (encrypt) {\r\n            desFunc(key1, in, inOff, out, outOff);\r\n            desFunc(key2, out, outOff, out, outOff);\r\n            desFunc(key3, out, outOff, out, outOff);\r\n        } else {\r\n            desFunc(key3, in, inOff, out, outOff);\r\n            desFunc(key2, out, outOff, out, outOff);\r\n            desFunc(key1, out, outOff, out, outOff);\r\n        }\r\n    }\r\n\r\n    public void reset() {\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/cipher/NullCipher.java",
    "content": "package ch.ethz.ssh2.crypto.cipher;\r\n\r\n/**\r\n * NullCipher.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: NullCipher.java,v 1.3 2005/12/07 10:25:48 cplattne Exp $\r\n */\r\npublic class NullCipher implements BlockCipher {\r\n    private int blockSize = 8;\r\n\r\n    public NullCipher() {\r\n    }\r\n\r\n    public NullCipher(int blockSize) {\r\n        this.blockSize = blockSize;\r\n    }\r\n\r\n    public void init(boolean forEncryption, byte[] key) {\r\n    }\r\n\r\n    public int getBlockSize() {\r\n        return blockSize;\r\n    }\r\n\r\n    public void transformBlock(byte[] src, int srcoff, byte[] dst, int dstoff) {\r\n        System.arraycopy(src, srcoff, dst, dstoff, blockSize);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/dh/DhExchange.java",
    "content": "package ch.ethz.ssh2.crypto.dh;\r\n\r\nimport ch.ethz.ssh2.crypto.digest.HashForSSH2Types;\r\nimport ch.ethz.ssh2.log.Logger;\r\n\r\nimport java.math.BigInteger;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * DhExchange.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DhExchange.java,v 1.5 2006/02/14 19:43:15 cplattne Exp $\r\n */\r\npublic class DhExchange {\r\n    static final BigInteger p1, p14;\r\n\r\n\t/* Given by the standard */\r\n    static final BigInteger g;\r\n    private static final Logger log = Logger.getLogger(DhExchange.class);\r\n\r\n    static {\r\n        final String p1_string = \"17976931348623159077083915679378745319786029604875\"\r\n                + \"60117064444236841971802161585193689478337958649255415021805654859805036464\"\r\n                + \"40548199239100050792877003355816639229553136239076508735759914822574862575\"\r\n                + \"00742530207744771258955095793777842444242661733472762929938766870920560605\"\r\n                + \"0270810842907692932019128194467627007\";\r\n\r\n        final String p14_string = \"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129\"\r\n                + \"024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0\"\r\n                + \"A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB\"\r\n                + \"6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A\"\r\n                + \"163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208\"\r\n                + \"552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36C\"\r\n                + \"E3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558171\"\r\n                + \"83995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF\";\r\n\r\n        p1 = new BigInteger(p1_string);\r\n        p14 = new BigInteger(p14_string, 16);\r\n        g = new BigInteger(\"2\");\r\n    }\r\n\r\n\t/* Client public and private */\r\n\r\n    BigInteger p;\r\n    BigInteger e;\r\n\r\n\t/* Server public */\r\n    BigInteger x;\r\n\r\n\t/* Shared secret */\r\n    BigInteger f;\r\n    BigInteger k;\r\n\r\n    public DhExchange() {\r\n    }\r\n\r\n    public void init(int group, SecureRandom rnd) {\r\n        k = null;\r\n\r\n        if (group == 1)\r\n            p = p1;\r\n        else if (group == 14)\r\n            p = p14;\r\n        else\r\n            throw new IllegalArgumentException(\"Unknown DH group \" + group);\r\n\r\n        x = new BigInteger(p.bitLength() - 1, rnd);\r\n\r\n        e = g.modPow(x, p);\r\n    }\r\n\r\n    /**\r\n     * @return Returns the e.\r\n     * @throws IllegalStateException\r\n     */\r\n    public BigInteger getE() {\r\n        if (e == null)\r\n            throw new IllegalStateException(\"DhDsaExchange not initialized!\");\r\n\r\n        return e;\r\n    }\r\n\r\n    /**\r\n     * @return Returns the shared secret k.\r\n     * @throws IllegalStateException\r\n     */\r\n    public BigInteger getK() {\r\n        if (k == null)\r\n            throw new IllegalStateException(\"Shared secret not yet known, need f first!\");\r\n\r\n        return k;\r\n    }\r\n\r\n    /**\r\n     * @param f\r\n     */\r\n    public void setF(BigInteger f) {\r\n        if (e == null)\r\n            throw new IllegalStateException(\"DhDsaExchange not initialized!\");\r\n\r\n        BigInteger zero = BigInteger.valueOf(0);\r\n\r\n        if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0)\r\n            throw new IllegalArgumentException(\"Invalid f specified!\");\r\n\r\n        this.f = f;\r\n        this.k = f.modPow(x, p);\r\n    }\r\n\r\n    public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload,\r\n                             byte[] serverKexPayload, byte[] hostKey) {\r\n        HashForSSH2Types hash = new HashForSSH2Types(\"SHA1\");\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(90, \"Client: '\" + new String(clientversion) + \"'\");\r\n            log.log(90, \"Server: '\" + new String(serverversion) + \"'\");\r\n        }\r\n\r\n        hash.updateByteString(clientversion);\r\n        hash.updateByteString(serverversion);\r\n        hash.updateByteString(clientKexPayload);\r\n        hash.updateByteString(serverKexPayload);\r\n        hash.updateByteString(hostKey);\r\n        hash.updateBigInt(e);\r\n        hash.updateBigInt(f);\r\n        hash.updateBigInt(k);\r\n\r\n        return hash.getDigest();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/dh/DhGroupExchange.java",
    "content": "package ch.ethz.ssh2.crypto.dh;\r\n\r\nimport ch.ethz.ssh2.DHGexParameters;\r\nimport ch.ethz.ssh2.crypto.digest.HashForSSH2Types;\r\n\r\nimport java.math.BigInteger;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * DhGroupExchange.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DhGroupExchange.java,v 1.6 2006/09/20 12:51:37 cplattne Exp $\r\n */\r\npublic class DhGroupExchange {\r\n    /* Given by the standard */\r\n\r\n    private BigInteger p;\r\n    private BigInteger g;\r\n\r\n\t/* Client public and private */\r\n\r\n    private BigInteger e;\r\n    private BigInteger x;\r\n\r\n\t/* Server public */\r\n\r\n    private BigInteger f;\r\n\r\n\t/* Shared secret */\r\n\r\n    private BigInteger k;\r\n\r\n    public DhGroupExchange(BigInteger p, BigInteger g) {\r\n        this.p = p;\r\n        this.g = g;\r\n    }\r\n\r\n    public void init(SecureRandom rnd) {\r\n        k = null;\r\n\r\n        x = new BigInteger(p.bitLength() - 1, rnd);\r\n        e = g.modPow(x, p);\r\n    }\r\n\r\n    /**\r\n     * @return Returns the e.\r\n     */\r\n    public BigInteger getE() {\r\n        if (e == null)\r\n            throw new IllegalStateException(\"Not initialized!\");\r\n\r\n        return e;\r\n    }\r\n\r\n    /**\r\n     * @return Returns the shared secret k.\r\n     */\r\n    public BigInteger getK() {\r\n        if (k == null)\r\n            throw new IllegalStateException(\"Shared secret not yet known, need f first!\");\r\n\r\n        return k;\r\n    }\r\n\r\n    /**\r\n     * Sets f and calculates the shared secret.\r\n     */\r\n    public void setF(BigInteger f) {\r\n        if (e == null)\r\n            throw new IllegalStateException(\"Not initialized!\");\r\n\r\n        BigInteger zero = BigInteger.valueOf(0);\r\n\r\n        if (zero.compareTo(f) >= 0 || p.compareTo(f) <= 0)\r\n            throw new IllegalArgumentException(\"Invalid f specified!\");\r\n\r\n        this.f = f;\r\n        this.k = f.modPow(x, p);\r\n    }\r\n\r\n    public byte[] calculateH(byte[] clientversion, byte[] serverversion, byte[] clientKexPayload,\r\n                             byte[] serverKexPayload, byte[] hostKey, DHGexParameters para) {\r\n        HashForSSH2Types hash = new HashForSSH2Types(\"SHA1\");\r\n\r\n        hash.updateByteString(clientversion);\r\n        hash.updateByteString(serverversion);\r\n        hash.updateByteString(clientKexPayload);\r\n        hash.updateByteString(serverKexPayload);\r\n        hash.updateByteString(hostKey);\r\n        if (para.getMin_group_len() > 0)\r\n            hash.updateUINT32(para.getMin_group_len());\r\n        hash.updateUINT32(para.getPref_group_len());\r\n        if (para.getMax_group_len() > 0)\r\n            hash.updateUINT32(para.getMax_group_len());\r\n        hash.updateBigInt(p);\r\n        hash.updateBigInt(g);\r\n        hash.updateBigInt(e);\r\n        hash.updateBigInt(f);\r\n        hash.updateBigInt(k);\r\n\r\n        return hash.getDigest();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/Digest.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\n/**\r\n * Digest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Digest.java,v 1.2 2005/08/11 12:47:29 cplattne Exp $\r\n */\r\npublic interface Digest {\r\n    public int getDigestLength();\r\n\r\n    public void update(byte b);\r\n\r\n    public void update(byte[] b);\r\n\r\n    public void update(byte b[], int off, int len);\r\n\r\n    public void reset();\r\n\r\n    public void digest(byte[] out);\r\n\r\n    public void digest(byte[] out, int off);\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/HMAC.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\n/**\r\n * HMAC.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: HMAC.java,v 1.2 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\npublic final class HMAC implements Digest {\r\n    Digest md;\r\n    byte[] k_xor_ipad;\r\n    byte[] k_xor_opad;\r\n\r\n    byte[] tmp;\r\n\r\n    int size;\r\n\r\n    public HMAC(Digest md, byte[] key, int size) {\r\n        this.md = md;\r\n        this.size = size;\r\n\r\n        tmp = new byte[md.getDigestLength()];\r\n\r\n        int BLOCKSIZE = 64;\r\n\r\n        k_xor_ipad = new byte[BLOCKSIZE];\r\n        k_xor_opad = new byte[BLOCKSIZE];\r\n\r\n        if (key.length > BLOCKSIZE) {\r\n            md.reset();\r\n            md.update(key);\r\n            md.digest(tmp);\r\n            key = tmp;\r\n        }\r\n\r\n        System.arraycopy(key, 0, k_xor_ipad, 0, key.length);\r\n        System.arraycopy(key, 0, k_xor_opad, 0, key.length);\r\n\r\n        for (int i = 0; i < BLOCKSIZE; i++) {\r\n            k_xor_ipad[i] ^= 0x36;\r\n            k_xor_opad[i] ^= 0x5C;\r\n        }\r\n        md.update(k_xor_ipad);\r\n    }\r\n\r\n    public final int getDigestLength() {\r\n        return size;\r\n    }\r\n\r\n    public final void update(byte b) {\r\n        md.update(b);\r\n    }\r\n\r\n    public final void update(byte[] b) {\r\n        md.update(b);\r\n    }\r\n\r\n    public final void update(byte[] b, int off, int len) {\r\n        md.update(b, off, len);\r\n    }\r\n\r\n    public final void reset() {\r\n        md.reset();\r\n        md.update(k_xor_ipad);\r\n    }\r\n\r\n    public final void digest(byte[] out) {\r\n        digest(out, 0);\r\n    }\r\n\r\n    public final void digest(byte[] out, int off) {\r\n        md.digest(tmp);\r\n\r\n        md.update(k_xor_opad);\r\n        md.update(tmp);\r\n\r\n        md.digest(tmp);\r\n\r\n        System.arraycopy(tmp, 0, out, off, size);\r\n\r\n        md.update(k_xor_ipad);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/HashForSSH2Types.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * HashForSSH2Types.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: HashForSSH2Types.java,v 1.3 2005/08/12 23:37:18 cplattne Exp $\r\n */\r\npublic class HashForSSH2Types {\r\n    Digest md;\r\n\r\n    public HashForSSH2Types(Digest md) {\r\n        this.md = md;\r\n    }\r\n\r\n    public HashForSSH2Types(String type) {\r\n        if (type.equals(\"SHA1\")) {\r\n            md = new SHA1();\r\n        } else if (type.equals(\"MD5\")) {\r\n            md = new MD5();\r\n        } else\r\n            throw new IllegalArgumentException(\"Unknown algorithm \" + type);\r\n    }\r\n\r\n    public void updateByte(byte b) {\r\n        /* HACK - to test it with J2ME */\r\n        byte[] tmp = new byte[1];\r\n        tmp[0] = b;\r\n        md.update(tmp);\r\n    }\r\n\r\n    public void updateBytes(byte[] b) {\r\n        md.update(b);\r\n    }\r\n\r\n    public void updateUINT32(int v) {\r\n        md.update((byte) (v >> 24));\r\n        md.update((byte) (v >> 16));\r\n        md.update((byte) (v >> 8));\r\n        md.update((byte) (v));\r\n    }\r\n\r\n    public void updateByteString(byte[] b) {\r\n        updateUINT32(b.length);\r\n        updateBytes(b);\r\n    }\r\n\r\n    public void updateBigInt(BigInteger b) {\r\n        updateByteString(b.toByteArray());\r\n    }\r\n\r\n    public void reset() {\r\n        md.reset();\r\n    }\r\n\r\n    public int getDigestLength() {\r\n        return md.getDigestLength();\r\n    }\r\n\r\n    public byte[] getDigest() {\r\n        byte[] tmp = new byte[md.getDigestLength()];\r\n        getDigest(tmp);\r\n        return tmp;\r\n    }\r\n\r\n    public void getDigest(byte[] out) {\r\n        getDigest(out, 0);\r\n    }\r\n\r\n    public void getDigest(byte[] out, int off) {\r\n        md.digest(out, off);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/MAC.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\n/**\r\n * MAC.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: MAC.java,v 1.4 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\npublic final class MAC {\r\n    Digest mac;\r\n    int size;\r\n\r\n    public MAC(String type, byte[] key) {\r\n        if (type.equals(\"hmac-sha1\")) {\r\n            mac = new HMAC(new SHA1(), key, 20);\r\n        } else if (type.equals(\"hmac-sha1-96\")) {\r\n            mac = new HMAC(new SHA1(), key, 12);\r\n        } else if (type.equals(\"hmac-md5\")) {\r\n            mac = new HMAC(new MD5(), key, 16);\r\n        } else if (type.equals(\"hmac-md5-96\")) {\r\n            mac = new HMAC(new MD5(), key, 12);\r\n        } else\r\n            throw new IllegalArgumentException(\"Unkown algorithm \" + type);\r\n\r\n        size = mac.getDigestLength();\r\n    }\r\n\r\n    public final static String[] getMacList() {\r\n        /* Higher Priority First */\r\n\r\n        return new String[]{\"hmac-sha1-96\", \"hmac-sha1\", \"hmac-md5-96\", \"hmac-md5\"};\r\n    }\r\n\r\n    public final static void checkMacList(String[] macs) {\r\n        for (int i = 0; i < macs.length; i++)\r\n            getKeyLen(macs[i]);\r\n    }\r\n\r\n    public final static int getKeyLen(String type) {\r\n        if (type.equals(\"hmac-sha1\"))\r\n            return 20;\r\n        if (type.equals(\"hmac-sha1-96\"))\r\n            return 20;\r\n        if (type.equals(\"hmac-md5\"))\r\n            return 16;\r\n        if (type.equals(\"hmac-md5-96\"))\r\n            return 16;\r\n        throw new IllegalArgumentException(\"Unkown algorithm \" + type);\r\n    }\r\n\r\n    public final void initMac(int seq) {\r\n        mac.reset();\r\n        mac.update((byte) (seq >> 24));\r\n        mac.update((byte) (seq >> 16));\r\n        mac.update((byte) (seq >> 8));\r\n        mac.update((byte) (seq));\r\n    }\r\n\r\n    public final void update(byte[] packetdata, int off, int len) {\r\n        mac.update(packetdata, off, len);\r\n    }\r\n\r\n    public final void getMac(byte[] out, int off) {\r\n        mac.digest(out, off);\r\n    }\r\n\r\n    public final int size() {\r\n        return size;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/MD5.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\n/**\r\n * MD5. Based on the example code in RFC 1321. Optimized (...a little).\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: MD5.java,v 1.2 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\n\r\n/*\r\n * The following disclaimer has been copied from RFC 1321:\r\n * \r\n * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights\r\n * reserved.\r\n * \r\n * License to copy and use this software is granted provided that it is\r\n * identified as the \"RSA Data Security, Inc. MD5 Message-Digest Algorithm\" in\r\n * all material mentioning or referencing this software or this function.\r\n * \r\n * License is also granted to make and use derivative works provided that such\r\n * works are identified as \"derived from the RSA Data Security, Inc. MD5\r\n * Message-Digest Algorithm\" in all material mentioning or referencing the\r\n * derived work.\r\n * \r\n * RSA Data Security, Inc. makes no representations concerning either the\r\n * merchantability of this software or the suitability of this software for any\r\n * particular purpose. It is provided \"as is\" without express or implied\r\n * warranty of any kind.\r\n * \r\n * These notices must be retained in any copies of any part of this\r\n * documentation and/or software.\r\n * \r\n */\r\n\r\npublic final class MD5 implements Digest {\r\n    private static final byte[] padding = new byte[]{(byte) 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r\n            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r\n            0, 0, 0, 0, 0, 0, 0, 0, 0, 0};\r\n    private final byte[] block = new byte[64];\r\n    private final int x[] = new int[16];\r\n    private int state0, state1, state2, state3;\r\n    private long count;\r\n\r\n    public MD5() {\r\n        reset();\r\n    }\r\n\r\n    private static final int FF(int a, int b, int c, int d, int x, int s, int ac) {\r\n        a += ((b & c) | ((~b) & d)) + x + ac;\r\n        return ((a << s) | (a >>> (32 - s))) + b;\r\n    }\r\n\r\n    private static final int GG(int a, int b, int c, int d, int x, int s, int ac) {\r\n        a += ((b & d) | (c & (~d))) + x + ac;\r\n        return ((a << s) | (a >>> (32 - s))) + b;\r\n    }\r\n\r\n    private static final int HH(int a, int b, int c, int d, int x, int s, int ac) {\r\n        a += (b ^ c ^ d) + x + ac;\r\n        return ((a << s) | (a >>> (32 - s))) + b;\r\n    }\r\n\r\n    private static final int II(int a, int b, int c, int d, int x, int s, int ac) {\r\n        a += (c ^ (b | (~d))) + x + ac;\r\n        return ((a << s) | (a >>> (32 - s))) + b;\r\n    }\r\n\r\n    private static final void encode(byte[] dst, int dstoff, int word) {\r\n        dst[dstoff] = (byte) (word);\r\n        dst[dstoff + 1] = (byte) (word >> 8);\r\n        dst[dstoff + 2] = (byte) (word >> 16);\r\n        dst[dstoff + 3] = (byte) (word >> 24);\r\n    }\r\n\r\n    private final void transform(byte[] src, int pos) {\r\n        int a = state0;\r\n        int b = state1;\r\n        int c = state2;\r\n        int d = state3;\r\n\r\n        for (int i = 0; i < 16; i++, pos += 4) {\r\n            x[i] = (src[pos] & 0xff) | ((src[pos + 1] & 0xff) << 8) | ((src[pos + 2] & 0xff) << 16)\r\n                    | ((src[pos + 3] & 0xff) << 24);\r\n        }\r\n\r\n\t\t/* Round 1 */\r\n\r\n        a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */\r\n        d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */\r\n        c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */\r\n        b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */\r\n        a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */\r\n        d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */\r\n        c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */\r\n        b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */\r\n        a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */\r\n        d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */\r\n        c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */\r\n        b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */\r\n        a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */\r\n        d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */\r\n        c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */\r\n        b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */\r\n\r\n\t\t/* Round 2 */\r\n        a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */\r\n        d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */\r\n        c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */\r\n        b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */\r\n        a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */\r\n        d = GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */\r\n        c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */\r\n        b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */\r\n        a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */\r\n        d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */\r\n        c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */\r\n        b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */\r\n        a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */\r\n        d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */\r\n        c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */\r\n        b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */\r\n\r\n\t\t/* Round 3 */\r\n        a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */\r\n        d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */\r\n        c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */\r\n        b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */\r\n        a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */\r\n        d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */\r\n        c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */\r\n        b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */\r\n        a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */\r\n        d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */\r\n        c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */\r\n        b = HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */\r\n        a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */\r\n        d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */\r\n        c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */\r\n        b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */\r\n\r\n\t\t/* Round 4 */\r\n        a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */\r\n        d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */\r\n        c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */\r\n        b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */\r\n        a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */\r\n        d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */\r\n        c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */\r\n        b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */\r\n        a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */\r\n        d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */\r\n        c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */\r\n        b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */\r\n        a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */\r\n        d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */\r\n        c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */\r\n        b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */\r\n\r\n        state0 += a;\r\n        state1 += b;\r\n        state2 += c;\r\n        state3 += d;\r\n    }\r\n\r\n    public final void reset() {\r\n        count = 0;\r\n\r\n        state0 = 0x67452301;\r\n        state1 = 0xefcdab89;\r\n        state2 = 0x98badcfe;\r\n        state3 = 0x10325476;\r\n\r\n\t\t/* Clear traces in memory... */\r\n\r\n        for (int i = 0; i < 16; i++)\r\n            x[i] = 0;\r\n    }\r\n\r\n    public final void update(byte b) {\r\n        final int space = 64 - ((int) (count & 0x3f));\r\n\r\n        count++;\r\n\r\n        block[64 - space] = b;\r\n\r\n        if (space == 1)\r\n            transform(block, 0);\r\n    }\r\n\r\n    public final void update(byte[] buff, int pos, int len) {\r\n        int space = 64 - ((int) (count & 0x3f));\r\n\r\n        count += len;\r\n\r\n        while (len > 0) {\r\n            if (len < space) {\r\n                System.arraycopy(buff, pos, block, 64 - space, len);\r\n                break;\r\n            }\r\n\r\n            if (space == 64) {\r\n                transform(buff, pos);\r\n            } else {\r\n                System.arraycopy(buff, pos, block, 64 - space, space);\r\n                transform(block, 0);\r\n            }\r\n\r\n            pos += space;\r\n            len -= space;\r\n            space = 64;\r\n        }\r\n    }\r\n\r\n    public final void update(byte[] b) {\r\n        update(b, 0, b.length);\r\n    }\r\n\r\n    public final void digest(byte[] dst, int pos) {\r\n        byte[] bits = new byte[8];\r\n\r\n        encode(bits, 0, (int) (count << 3));\r\n        encode(bits, 4, (int) (count >> 29));\r\n\r\n        int idx = (int) count & 0x3f;\r\n        int padLen = (idx < 56) ? (56 - idx) : (120 - idx);\r\n\r\n        update(padding, 0, padLen);\r\n        update(bits, 0, 8);\r\n\r\n        encode(dst, pos, state0);\r\n        encode(dst, pos + 4, state1);\r\n        encode(dst, pos + 8, state2);\r\n        encode(dst, pos + 12, state3);\r\n\r\n        reset();\r\n    }\r\n\r\n    public final void digest(byte[] dst) {\r\n        digest(dst, 0);\r\n    }\r\n\r\n    public final int getDigestLength() {\r\n        return 16;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/crypto/digest/SHA1.java",
    "content": "package ch.ethz.ssh2.crypto.digest;\r\n\r\n/**\r\n * SHA-1 implementation based on FIPS PUB 180-1.\r\n * <p>\r\n * (http://www.itl.nist.gov/fipspubs/fip180-1.htm)\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: SHA1.java,v 1.4 2006/02/02 09:11:03 cplattne Exp $\r\n */\r\npublic final class SHA1 implements Digest {\r\n    private final byte msg[] = new byte[64];\r\n    private final int[] w = new int[80];\r\n    private int H0, H1, H2, H3, H4;\r\n    private int currentPos;\r\n    private long currentLen;\r\n\r\n    public SHA1() {\r\n        reset();\r\n    }\r\n\r\n    private static final String toHexString(byte[] b) {\r\n        final String hexChar = \"0123456789ABCDEF\";\r\n\r\n        StringBuffer sb = new StringBuffer();\r\n        for (int i = 0; i < b.length; i++) {\r\n            sb.append(hexChar.charAt((b[i] >> 4) & 0x0f));\r\n            sb.append(hexChar.charAt(b[i] & 0x0f));\r\n        }\r\n        return sb.toString();\r\n    }\r\n\r\n    public static void main(String[] args) {\r\n        SHA1 sha = new SHA1();\r\n\r\n        byte[] dig1 = new byte[20];\r\n        byte[] dig2 = new byte[20];\r\n        byte[] dig3 = new byte[20];\r\n\r\n\t\t/*\r\n         * We do not specify a charset name for getBytes(), since we assume that\r\n\t\t * the JVM's default encoder maps the _used_ ASCII characters exactly as\r\n\t\t * getBytes(\"US-ASCII\") would do. (Ah, yes, too lazy to catch the\r\n\t\t * exception that can be thrown by getBytes(\"US-ASCII\")). Note: This has\r\n\t\t * no effect on the SHA-1 implementation, this is just for the following\r\n\t\t * test code.\r\n\t\t */\r\n\r\n        sha.update(\"abc\".getBytes());\r\n        sha.digest(dig1);\r\n\r\n        sha.update(\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\".getBytes());\r\n        sha.digest(dig2);\r\n\r\n        for (int i = 0; i < 1000000; i++)\r\n            sha.update((byte) 'a');\r\n        sha.digest(dig3);\r\n\r\n        String dig1_res = toHexString(dig1);\r\n        String dig2_res = toHexString(dig2);\r\n        String dig3_res = toHexString(dig3);\r\n\r\n        String dig1_ref = \"A9993E364706816ABA3E25717850C26C9CD0D89D\";\r\n        String dig2_ref = \"84983E441C3BD26EBAAE4AA1F95129E5E54670F1\";\r\n        String dig3_ref = \"34AA973CD4C4DAA4F61EEB2BDBAD27316534016F\";\r\n\r\n        if (dig1_res.equals(dig1_ref))\r\n            System.out.println(\"SHA-1 Test 1 OK.\");\r\n        else\r\n            System.out.println(\"SHA-1 Test 1 FAILED.\");\r\n\r\n        if (dig2_res.equals(dig2_ref))\r\n            System.out.println(\"SHA-1 Test 2 OK.\");\r\n        else\r\n            System.out.println(\"SHA-1 Test 2 FAILED.\");\r\n\r\n        if (dig3_res.equals(dig3_ref))\r\n            System.out.println(\"SHA-1 Test 3 OK.\");\r\n        else\r\n            System.out.println(\"SHA-1 Test 3 FAILED.\");\r\n\r\n    }\r\n\r\n    public final int getDigestLength() {\r\n        return 20;\r\n    }\r\n\r\n    public final void reset() {\r\n        H0 = 0x67452301;\r\n        H1 = 0xEFCDAB89;\r\n        H2 = 0x98BADCFE;\r\n        H3 = 0x10325476;\r\n        H4 = 0xC3D2E1F0;\r\n\r\n        currentPos = 0;\r\n        currentLen = 0;\r\n    }\r\n\r\n    public final void update(byte b[], int off, int len) {\r\n        for (int i = off; i < (off + len); i++)\r\n            update(b[i]);\r\n    }\r\n\r\n    public final void update(byte b[]) {\r\n        for (int i = 0; i < b.length; i++)\r\n            update(b[i]);\r\n    }\r\n\r\n    public final void update(byte b) {\r\n        // System.out.println(pos + \"->\" + b);\r\n        msg[currentPos++] = b;\r\n        currentLen += 8;\r\n        if (currentPos == 64) {\r\n            perform();\r\n            currentPos = 0;\r\n        }\r\n    }\r\n\r\n    private final void putInt(byte[] b, int pos, int val) {\r\n        b[pos] = (byte) (val >> 24);\r\n        b[pos + 1] = (byte) (val >> 16);\r\n        b[pos + 2] = (byte) (val >> 8);\r\n        b[pos + 3] = (byte) val;\r\n    }\r\n\r\n    public final void digest(byte[] out) {\r\n        digest(out, 0);\r\n    }\r\n\r\n    public final void digest(byte[] out, int off) {\r\n        long l = currentLen;\r\n\r\n        update((byte) 0x80);\r\n\r\n        // padding could be done more efficiently...\r\n        while (currentPos != 56)\r\n            update((byte) 0);\r\n\r\n        update((byte) (l >> 56));\r\n        update((byte) (l >> 48));\r\n        update((byte) (l >> 40));\r\n        update((byte) (l >> 32));\r\n\r\n        update((byte) (l >> 24));\r\n        update((byte) (l >> 16));\r\n        update((byte) (l >> 8));\r\n        update((byte) (l));\r\n\r\n        // debug(80, H0, H1, H2, H3, H4);\r\n\r\n        putInt(out, off, H0);\r\n        putInt(out, off + 4, H1);\r\n        putInt(out, off + 8, H2);\r\n        putInt(out, off + 12, H3);\r\n        putInt(out, off + 16, H4);\r\n\r\n        reset();\r\n    }\r\n\r\n    /*\r\n     * private void debug(int t, int A, int B, int C, int D, int E) {\r\n     * System.out.println(t + \": \" + Integer.toHexString(A).toUpperCase() + \", \" +\r\n     * Integer.toHexString(B).toUpperCase() + \", \" +\r\n     * Integer.toHexString(C).toUpperCase() + \",\" +\r\n     * Integer.toHexString(D).toUpperCase() + \", \" +\r\n     * Integer.toHexString(E).toUpperCase()); }\r\n     */\r\n    private final void perform() {\r\n        for (int i = 0; i < 16; i++)\r\n            w[i] = ((msg[i * 4] & 0xff) << 24) | ((msg[i * 4 + 1] & 0xff) << 16) | ((msg[i * 4 + 2] & 0xff) << 8)\r\n                    | ((msg[i * 4 + 3] & 0xff));\r\n\r\n        for (int t = 16; t < 80; t++) {\r\n            int x = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];\r\n            w[t] = ((x << 1) | (x >>> 31));\r\n        }\r\n\r\n        int A = H0;\r\n        int B = H1;\r\n        int C = H2;\r\n        int D = H3;\r\n        int E = H4;\r\n\r\n        int T;\r\n\r\n        for (int t = 0; t <= 19; t++) {\r\n            T = ((A << 5) | (A >>> 27)) + ((B & C) | ((~B) & D)) + E + w[t] + 0x5A827999;\r\n            E = D;\r\n            D = C;\r\n            C = ((B << 30) | (B >>> 2));\r\n            B = A;\r\n            A = T;\r\n            // debug(t, A, B, C, D, E);\r\n        }\r\n\r\n        for (int t = 20; t <= 39; t++) {\r\n            T = ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + E + w[t] + 0x6ED9EBA1;\r\n            E = D;\r\n            D = C;\r\n            C = ((B << 30) | (B >>> 2));\r\n            B = A;\r\n            A = T;\r\n            // debug(t, A, B, C, D, E);\r\n        }\r\n\r\n        for (int t = 40; t <= 59; t++) {\r\n            T = ((A << 5) | (A >>> 27)) + ((B & C) | (B & D) | (C & D)) + E + w[t] + 0x8F1BBCDC;\r\n            E = D;\r\n            D = C;\r\n            C = ((B << 30) | (B >>> 2));\r\n            B = A;\r\n            A = T;\r\n            // debug(t, A, B, C, D, E);\r\n        }\r\n\r\n        for (int t = 60; t <= 79; t++) {\r\n            T = ((A << 5) | (A >>> 27)) + (B ^ C ^ D) + E + w[t] + 0xCA62C1D6;\r\n            E = D;\r\n            D = C;\r\n            C = ((B << 30) | (B >>> 2));\r\n            B = A;\r\n            A = T;\r\n            // debug(t, A, B, C, D, E);\r\n        }\r\n\r\n        H0 = H0 + A;\r\n        H1 = H1 + B;\r\n        H2 = H2 + C;\r\n        H3 = H3 + D;\r\n        H4 = H4 + E;\r\n\r\n        // debug(80, H0, H1, H2, H3, H4);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/log/Logger.java",
    "content": "package ch.ethz.ssh2.log;\r\n\r\n/**\r\n * Logger - a very simple logger, mainly used during development.\r\n * Is not based on log4j (to reduce external dependencies).\r\n * However, if needed, something like log4j could easily be\r\n * hooked in.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Logger.java,v 1.7 2005/12/07 13:14:24 cplattne Exp $\r\n */\r\n\r\npublic class Logger {\r\n    private static final boolean enabled = false;\r\n    private static final int logLevel = 99;\r\n\r\n    private String className;\r\n\r\n    public Logger(Class x) {\r\n        this.className = x.getName();\r\n    }\r\n\r\n    public final static Logger getLogger(Class x) {\r\n        return new Logger(x);\r\n    }\r\n\r\n    public final boolean isEnabled() {\r\n        return enabled;\r\n    }\r\n\r\n    public void log(int level, String message) {\r\n        long now = System.currentTimeMillis();\r\n\r\n        if ((enabled) && (level <= logLevel)) {\r\n            synchronized (this) {\r\n                System.err.println(now + \" : \" + className + \": \" + message);\r\n                // or send it to log4j or whatever...\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketChannelOpenConfirmation.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketChannelOpenConfirmation.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketChannelOpenConfirmation.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketChannelOpenConfirmation {\r\n    public int recipientChannelID;\r\n    public int senderChannelID;\r\n    public int initialWindowSize;\r\n    public int maxPacketSize;\r\n    byte[] payload;\r\n\r\n    public PacketChannelOpenConfirmation(int recipientChannelID, int senderChannelID, int initialWindowSize,\r\n                                         int maxPacketSize) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.senderChannelID = senderChannelID;\r\n        this.initialWindowSize = initialWindowSize;\r\n        this.maxPacketSize = maxPacketSize;\r\n    }\r\n\r\n    public PacketChannelOpenConfirmation(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION)\r\n            throw new IOException(\r\n                    \"This is not a SSH_MSG_CHANNEL_OPEN_CONFIRMATION! (\"\r\n                            + packet_type + \")\");\r\n\r\n        recipientChannelID = tr.readUINT32();\r\n        senderChannelID = tr.readUINT32();\r\n        initialWindowSize = tr.readUINT32();\r\n        maxPacketSize = tr.readUINT32();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_CONFIRMATION);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeUINT32(senderChannelID);\r\n            tw.writeUINT32(initialWindowSize);\r\n            tw.writeUINT32(maxPacketSize);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketChannelOpenFailure.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketChannelOpenFailure.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketChannelOpenFailure.java,v 1.1 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class PacketChannelOpenFailure {\r\n    public int recipientChannelID;\r\n    public int reasonCode;\r\n    public String description;\r\n    public String languageTag;\r\n    byte[] payload;\r\n\r\n    public PacketChannelOpenFailure(int recipientChannelID, int reasonCode, String description,\r\n                                    String languageTag) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.reasonCode = reasonCode;\r\n        this.description = description;\r\n        this.languageTag = languageTag;\r\n    }\r\n\r\n    public PacketChannelOpenFailure(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN_FAILURE)\r\n            throw new IOException(\r\n                    \"This is not a SSH_MSG_CHANNEL_OPEN_FAILURE! (\"\r\n                            + packet_type + \")\");\r\n\r\n        recipientChannelID = tr.readUINT32();\r\n        reasonCode = tr.readUINT32();\r\n        description = tr.readString();\r\n        languageTag = tr.readString();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_CHANNEL_OPEN_FAILURE packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN_FAILURE);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeUINT32(reasonCode);\r\n            tw.writeString(description);\r\n            tw.writeString(languageTag);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketChannelWindowAdjust.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketChannelWindowAdjust.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketChannelWindowAdjust.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketChannelWindowAdjust {\r\n    public int recipientChannelID;\r\n    public int windowChange;\r\n    byte[] payload;\r\n\r\n    public PacketChannelWindowAdjust(int recipientChannelID, int windowChange) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.windowChange = windowChange;\r\n    }\r\n\r\n    public PacketChannelWindowAdjust(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST)\r\n            throw new IOException(\r\n                    \"This is not a SSH_MSG_CHANNEL_WINDOW_ADJUST! (\"\r\n                            + packet_type + \")\");\r\n\r\n        recipientChannelID = tr.readUINT32();\r\n        windowChange = tr.readUINT32();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_CHANNEL_WINDOW_ADJUST packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_WINDOW_ADJUST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeUINT32(windowChange);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketDisconnect.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketDisconnect.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketDisconnect.java,v 1.3 2005/08/29 14:24:58 cplattne Exp $\r\n */\r\npublic class PacketDisconnect {\r\n    byte[] payload;\r\n\r\n    int reason;\r\n    String desc;\r\n    String lang;\r\n\r\n    public PacketDisconnect(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_DISCONNECT)\r\n            throw new IOException(\"This is not a Disconnect Packet! (\"\r\n                    + packet_type + \")\");\r\n\r\n        reason = tr.readUINT32();\r\n        desc = tr.readString();\r\n        lang = tr.readString();\r\n    }\r\n\r\n    public PacketDisconnect(int reason, String desc, String lang) {\r\n        this.reason = reason;\r\n        this.desc = desc;\r\n        this.lang = lang;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_DISCONNECT);\r\n            tw.writeUINT32(reason);\r\n            tw.writeString(desc);\r\n            tw.writeString(lang);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketGlobalCancelForwardRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketGlobalCancelForwardRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketGlobalCancelForwardRequest.java,v 1.1 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class PacketGlobalCancelForwardRequest {\r\n    public boolean wantReply;\r\n    public String bindAddress;\r\n    public int bindPort;\r\n    byte[] payload;\r\n\r\n    public PacketGlobalCancelForwardRequest(boolean wantReply, String bindAddress, int bindPort) {\r\n        this.wantReply = wantReply;\r\n        this.bindAddress = bindAddress;\r\n        this.bindPort = bindPort;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST);\r\n\r\n            tw.writeString(\"cancel-tcpip-forward\");\r\n            tw.writeBoolean(wantReply);\r\n            tw.writeString(bindAddress);\r\n            tw.writeUINT32(bindPort);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketGlobalForwardRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketGlobalForwardRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketGlobalForwardRequest.java,v 1.1 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class PacketGlobalForwardRequest {\r\n    public boolean wantReply;\r\n    public String bindAddress;\r\n    public int bindPort;\r\n    byte[] payload;\r\n\r\n    public PacketGlobalForwardRequest(boolean wantReply, String bindAddress, int bindPort) {\r\n        this.wantReply = wantReply;\r\n        this.bindAddress = bindAddress;\r\n        this.bindPort = bindPort;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_GLOBAL_REQUEST);\r\n\r\n            tw.writeString(\"tcpip-forward\");\r\n            tw.writeBoolean(wantReply);\r\n            tw.writeString(bindAddress);\r\n            tw.writeUINT32(bindPort);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketIgnore.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketIgnore.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketIgnore.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketIgnore {\r\n    byte[] payload;\r\n\r\n    byte[] body;\r\n\r\n    public PacketIgnore(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_IGNORE)\r\n            throw new IOException(\"This is not a SSH_MSG_IGNORE packet! (\" + packet_type + \")\");\r\n\r\n\t\t/* Could parse String body */\r\n    }\r\n\r\n    public void setBody(byte[] body) {\r\n        this.body = body;\r\n        payload = null;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_IGNORE);\r\n            tw.writeString(body, 0, body.length);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDHInit.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PacketKexDHInit.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDHInit.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDHInit {\r\n    byte[] payload;\r\n\r\n    BigInteger e;\r\n\r\n    public PacketKexDHInit(BigInteger e) {\r\n        this.e = e;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_KEXDH_INIT);\r\n            tw.writeMPInt(e);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDHReply.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PacketKexDHReply.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDHReply.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDHReply {\r\n    byte[] payload;\r\n\r\n    byte[] hostKey;\r\n    BigInteger f;\r\n    byte[] signature;\r\n\r\n    public PacketKexDHReply(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_KEXDH_REPLY)\r\n            throw new IOException(\"This is not a SSH_MSG_KEXDH_REPLY! (\"\r\n                    + packet_type + \")\");\r\n\r\n        hostKey = tr.readByteString();\r\n        f = tr.readMPINT();\r\n        signature = tr.readByteString();\r\n\r\n        if (tr.remain() != 0) throw new IOException(\"PADDING IN SSH_MSG_KEXDH_REPLY!\");\r\n    }\r\n\r\n    public BigInteger getF() {\r\n        return f;\r\n    }\r\n\r\n    public byte[] getHostKey() {\r\n        return hostKey;\r\n    }\r\n\r\n    public byte[] getSignature() {\r\n        return signature;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDhGexGroup.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PacketKexDhGexGroup.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDhGexGroup.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDhGexGroup {\r\n    byte[] payload;\r\n\r\n    BigInteger p;\r\n    BigInteger g;\r\n\r\n    public PacketKexDhGexGroup(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_GROUP)\r\n            throw new IllegalArgumentException(\r\n                    \"This is not a SSH_MSG_KEX_DH_GEX_GROUP! (\" + packet_type\r\n                            + \")\");\r\n\r\n        p = tr.readMPINT();\r\n        g = tr.readMPINT();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"PADDING IN SSH_MSG_KEX_DH_GEX_GROUP!\");\r\n    }\r\n\r\n    public BigInteger getG() {\r\n        return g;\r\n    }\r\n\r\n    public BigInteger getP() {\r\n        return p;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDhGexInit.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PacketKexDhGexInit.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDhGexInit.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDhGexInit {\r\n    byte[] payload;\r\n\r\n    BigInteger e;\r\n\r\n    public PacketKexDhGexInit(BigInteger e) {\r\n        this.e = e;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_INIT);\r\n            tw.writeMPInt(e);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDhGexReply.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * PacketKexDhGexReply.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDhGexReply.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDhGexReply {\r\n    byte[] payload;\r\n\r\n    byte[] hostKey;\r\n    BigInteger f;\r\n    byte[] signature;\r\n\r\n    public PacketKexDhGexReply(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_KEX_DH_GEX_REPLY)\r\n            throw new IOException(\"This is not a SSH_MSG_KEX_DH_GEX_REPLY! (\" + packet_type + \")\");\r\n\r\n        hostKey = tr.readByteString();\r\n        f = tr.readMPINT();\r\n        signature = tr.readByteString();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"PADDING IN SSH_MSG_KEX_DH_GEX_REPLY!\");\r\n    }\r\n\r\n    public BigInteger getF() {\r\n        return f;\r\n    }\r\n\r\n    public byte[] getHostKey() {\r\n        return hostKey;\r\n    }\r\n\r\n    public byte[] getSignature() {\r\n        return signature;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDhGexRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport ch.ethz.ssh2.DHGexParameters;\r\n\r\n/**\r\n * PacketKexDhGexRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDhGexRequest.java,v 1.4 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketKexDhGexRequest {\r\n    byte[] payload;\r\n\r\n    int min;\r\n    int n;\r\n    int max;\r\n\r\n    public PacketKexDhGexRequest(DHGexParameters para) {\r\n        this.min = para.getMin_group_len();\r\n        this.n = para.getPref_group_len();\r\n        this.max = para.getMax_group_len();\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST);\r\n            tw.writeUINT32(min);\r\n            tw.writeUINT32(n);\r\n            tw.writeUINT32(max);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexDhGexRequestOld.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport ch.ethz.ssh2.DHGexParameters;\r\n\r\n/**\r\n * PacketKexDhGexRequestOld.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexDhGexRequestOld.java,v 1.2 2006/09/20 12:52:46 cplattne Exp $\r\n */\r\npublic class PacketKexDhGexRequestOld {\r\n    byte[] payload;\r\n\r\n    int n;\r\n\r\n    public PacketKexDhGexRequestOld(DHGexParameters para) {\r\n        this.n = para.getPref_group_len();\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_KEX_DH_GEX_REQUEST_OLD);\r\n            tw.writeUINT32(n);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketKexInit.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport ch.ethz.ssh2.crypto.CryptoWishList;\r\nimport ch.ethz.ssh2.transport.KexParameters;\r\n\r\nimport java.io.IOException;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * PacketKexInit.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketKexInit.java,v 1.4 2006/02/14 19:43:15 cplattne Exp $\r\n */\r\npublic class PacketKexInit {\r\n    byte[] payload;\r\n\r\n    KexParameters kp = new KexParameters();\r\n\r\n    public PacketKexInit(CryptoWishList cwl, SecureRandom rnd) {\r\n        kp.cookie = new byte[16];\r\n        rnd.nextBytes(kp.cookie);\r\n\r\n        kp.kex_algorithms = cwl.kexAlgorithms;\r\n        kp.server_host_key_algorithms = cwl.serverHostKeyAlgorithms;\r\n        kp.encryption_algorithms_client_to_server = cwl.c2s_enc_algos;\r\n        kp.encryption_algorithms_server_to_client = cwl.s2c_enc_algos;\r\n        kp.mac_algorithms_client_to_server = cwl.c2s_mac_algos;\r\n        kp.mac_algorithms_server_to_client = cwl.s2c_mac_algos;\r\n        kp.compression_algorithms_client_to_server = new String[]{\"none\"};\r\n        kp.compression_algorithms_server_to_client = new String[]{\"none\"};\r\n        kp.languages_client_to_server = new String[]{};\r\n        kp.languages_server_to_client = new String[]{};\r\n        kp.first_kex_packet_follows = false;\r\n        kp.reserved_field1 = 0;\r\n    }\r\n\r\n    public PacketKexInit(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_KEXINIT)\r\n            throw new IOException(\"This is not a KexInitPacket! (\" + packet_type + \")\");\r\n\r\n        kp.cookie = tr.readBytes(16);\r\n        kp.kex_algorithms = tr.readNameList();\r\n        kp.server_host_key_algorithms = tr.readNameList();\r\n        kp.encryption_algorithms_client_to_server = tr.readNameList();\r\n        kp.encryption_algorithms_server_to_client = tr.readNameList();\r\n        kp.mac_algorithms_client_to_server = tr.readNameList();\r\n        kp.mac_algorithms_server_to_client = tr.readNameList();\r\n        kp.compression_algorithms_client_to_server = tr.readNameList();\r\n        kp.compression_algorithms_server_to_client = tr.readNameList();\r\n        kp.languages_client_to_server = tr.readNameList();\r\n        kp.languages_server_to_client = tr.readNameList();\r\n        kp.first_kex_packet_follows = tr.readBoolean();\r\n        kp.reserved_field1 = tr.readUINT32();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in KexInitPacket!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_KEXINIT);\r\n            tw.writeBytes(kp.cookie, 0, 16);\r\n            tw.writeNameList(kp.kex_algorithms);\r\n            tw.writeNameList(kp.server_host_key_algorithms);\r\n            tw.writeNameList(kp.encryption_algorithms_client_to_server);\r\n            tw.writeNameList(kp.encryption_algorithms_server_to_client);\r\n            tw.writeNameList(kp.mac_algorithms_client_to_server);\r\n            tw.writeNameList(kp.mac_algorithms_server_to_client);\r\n            tw.writeNameList(kp.compression_algorithms_client_to_server);\r\n            tw.writeNameList(kp.compression_algorithms_server_to_client);\r\n            tw.writeNameList(kp.languages_client_to_server);\r\n            tw.writeNameList(kp.languages_server_to_client);\r\n            tw.writeBoolean(kp.first_kex_packet_follows);\r\n            tw.writeUINT32(kp.reserved_field1);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n\r\n    public KexParameters getKexParameters() {\r\n        return kp;\r\n    }\r\n\r\n    public String[] getCompression_algorithms_client_to_server() {\r\n        return kp.compression_algorithms_client_to_server;\r\n    }\r\n\r\n    public String[] getCompression_algorithms_server_to_client() {\r\n        return kp.compression_algorithms_server_to_client;\r\n    }\r\n\r\n    public byte[] getCookie() {\r\n        return kp.cookie;\r\n    }\r\n\r\n    public String[] getEncryption_algorithms_client_to_server() {\r\n        return kp.encryption_algorithms_client_to_server;\r\n    }\r\n\r\n    public String[] getEncryption_algorithms_server_to_client() {\r\n        return kp.encryption_algorithms_server_to_client;\r\n    }\r\n\r\n    public boolean isFirst_kex_packet_follows() {\r\n        return kp.first_kex_packet_follows;\r\n    }\r\n\r\n    public String[] getKex_algorithms() {\r\n        return kp.kex_algorithms;\r\n    }\r\n\r\n    public String[] getLanguages_client_to_server() {\r\n        return kp.languages_client_to_server;\r\n    }\r\n\r\n    public String[] getLanguages_server_to_client() {\r\n        return kp.languages_server_to_client;\r\n    }\r\n\r\n    public String[] getMac_algorithms_client_to_server() {\r\n        return kp.mac_algorithms_client_to_server;\r\n    }\r\n\r\n    public String[] getMac_algorithms_server_to_client() {\r\n        return kp.mac_algorithms_server_to_client;\r\n    }\r\n\r\n    public int getReserved_field1() {\r\n        return kp.reserved_field1;\r\n    }\r\n\r\n    public String[] getServer_host_key_algorithms() {\r\n        return kp.server_host_key_algorithms;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketNewKeys.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketNewKeys.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketNewKeys.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketNewKeys {\r\n    byte[] payload;\r\n\r\n    public PacketNewKeys() {\r\n    }\r\n\r\n    public PacketNewKeys(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_NEWKEYS)\r\n            throw new IOException(\"This is not a SSH_MSG_NEWKEYS! (\"\r\n                    + packet_type + \")\");\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_NEWKEYS packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_NEWKEYS);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketOpenDirectTCPIPChannel.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n\r\n/**\r\n * PacketOpenDirectTCPIPChannel.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketOpenDirectTCPIPChannel.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketOpenDirectTCPIPChannel {\r\n    byte[] payload;\r\n\r\n    int channelID;\r\n    int initialWindowSize;\r\n    int maxPacketSize;\r\n\r\n    String host_to_connect;\r\n    int port_to_connect;\r\n    String originator_IP_address;\r\n    int originator_port;\r\n\r\n    public PacketOpenDirectTCPIPChannel(int channelID, int initialWindowSize, int maxPacketSize,\r\n                                        String host_to_connect, int port_to_connect, String originator_IP_address,\r\n                                        int originator_port) {\r\n        this.channelID = channelID;\r\n        this.initialWindowSize = initialWindowSize;\r\n        this.maxPacketSize = maxPacketSize;\r\n        this.host_to_connect = host_to_connect;\r\n        this.port_to_connect = port_to_connect;\r\n        this.originator_IP_address = originator_IP_address;\r\n        this.originator_port = originator_port;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN);\r\n            tw.writeString(\"direct-tcpip\");\r\n            tw.writeUINT32(channelID);\r\n            tw.writeUINT32(initialWindowSize);\r\n            tw.writeUINT32(maxPacketSize);\r\n            tw.writeString(host_to_connect);\r\n            tw.writeUINT32(port_to_connect);\r\n            tw.writeString(originator_IP_address);\r\n            tw.writeUINT32(originator_port);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketOpenSessionChannel.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketOpenSessionChannel.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketOpenSessionChannel.java,v 1.2 2005/08/24 17:54:10 cplattne Exp $\r\n */\r\npublic class PacketOpenSessionChannel {\r\n    byte[] payload;\r\n\r\n    int channelID;\r\n    int initialWindowSize;\r\n    int maxPacketSize;\r\n\r\n    public PacketOpenSessionChannel(int channelID, int initialWindowSize,\r\n                                    int maxPacketSize) {\r\n        this.channelID = channelID;\r\n        this.initialWindowSize = initialWindowSize;\r\n        this.maxPacketSize = maxPacketSize;\r\n    }\r\n\r\n    public PacketOpenSessionChannel(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_CHANNEL_OPEN)\r\n            throw new IOException(\"This is not a SSH_MSG_CHANNEL_OPEN! (\"\r\n                    + packet_type + \")\");\r\n\r\n        channelID = tr.readUINT32();\r\n        initialWindowSize = tr.readUINT32();\r\n        maxPacketSize = tr.readUINT32();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_CHANNEL_OPEN packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_OPEN);\r\n            tw.writeString(\"session\");\r\n            tw.writeUINT32(channelID);\r\n            tw.writeUINT32(initialWindowSize);\r\n            tw.writeUINT32(maxPacketSize);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketServiceAccept.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketServiceAccept.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketServiceAccept.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketServiceAccept {\r\n    byte[] payload;\r\n\r\n    String serviceName;\r\n\r\n    public PacketServiceAccept(String serviceName) {\r\n        this.serviceName = serviceName;\r\n    }\r\n\r\n    public PacketServiceAccept(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_SERVICE_ACCEPT)\r\n            throw new IOException(\"This is not a SSH_MSG_SERVICE_ACCEPT! (\"\r\n                    + packet_type + \")\");\r\n\r\n        serviceName = tr.readString();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_SERVICE_ACCEPT packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_SERVICE_ACCEPT);\r\n            tw.writeString(serviceName);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketServiceRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketServiceRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketServiceRequest.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketServiceRequest {\r\n    byte[] payload;\r\n\r\n    String serviceName;\r\n\r\n    public PacketServiceRequest(String serviceName) {\r\n        this.serviceName = serviceName;\r\n    }\r\n\r\n    public PacketServiceRequest(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_SERVICE_REQUEST)\r\n            throw new IOException(\"This is not a SSH_MSG_SERVICE_REQUEST! (\"\r\n                    + packet_type + \")\");\r\n\r\n        serviceName = tr.readString();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_SERVICE_REQUEST packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_SERVICE_REQUEST);\r\n            tw.writeString(serviceName);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketSessionExecCommand.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n\r\n/**\r\n * PacketSessionExecCommand.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketSessionExecCommand.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketSessionExecCommand {\r\n    public int recipientChannelID;\r\n    public boolean wantReply;\r\n    public String command;\r\n    byte[] payload;\r\n\r\n    public PacketSessionExecCommand(int recipientChannelID, boolean wantReply, String command) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.wantReply = wantReply;\r\n        this.command = command;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeString(\"exec\");\r\n            tw.writeBoolean(wantReply);\r\n            tw.writeString(command);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketSessionPtyRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n\r\n/**\r\n * PacketSessionPtyRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketSessionPtyRequest.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketSessionPtyRequest {\r\n    public int recipientChannelID;\r\n    public boolean wantReply;\r\n    public String term;\r\n    public int character_width;\r\n    public int character_height;\r\n    public int pixel_width;\r\n    public int pixel_height;\r\n    public byte[] terminal_modes;\r\n    byte[] payload;\r\n\r\n    public PacketSessionPtyRequest(int recipientChannelID, boolean wantReply, String term,\r\n                                   int character_width, int character_height, int pixel_width, int pixel_height,\r\n                                   byte[] terminal_modes) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.wantReply = wantReply;\r\n        this.term = term;\r\n        this.character_width = character_width;\r\n        this.character_height = character_height;\r\n        this.pixel_width = pixel_width;\r\n        this.pixel_height = pixel_height;\r\n        this.terminal_modes = terminal_modes;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeString(\"pty-req\");\r\n            tw.writeBoolean(wantReply);\r\n            tw.writeString(term);\r\n            tw.writeUINT32(character_width);\r\n            tw.writeUINT32(character_height);\r\n            tw.writeUINT32(pixel_width);\r\n            tw.writeUINT32(pixel_height);\r\n            tw.writeString(terminal_modes, 0, terminal_modes.length);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketSessionStartShell.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketSessionStartShell.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketSessionStartShell.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketSessionStartShell {\r\n    public int recipientChannelID;\r\n    public boolean wantReply;\r\n    byte[] payload;\r\n\r\n    public PacketSessionStartShell(int recipientChannelID, boolean wantReply) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.wantReply = wantReply;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeString(\"shell\");\r\n            tw.writeBoolean(wantReply);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketSessionSubsystemRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n\r\n/**\r\n * PacketSessionSubsystemRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketSessionSubsystemRequest.java,v 1.2 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketSessionSubsystemRequest {\r\n    public int recipientChannelID;\r\n    public boolean wantReply;\r\n    public String subsystem;\r\n    byte[] payload;\r\n\r\n    public PacketSessionSubsystemRequest(int recipientChannelID, boolean wantReply, String subsystem) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.wantReply = wantReply;\r\n        this.subsystem = subsystem;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeString(\"subsystem\");\r\n            tw.writeBoolean(wantReply);\r\n            tw.writeString(subsystem);\r\n            payload = tw.getBytes();\r\n            tw.getBytes(payload);\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketSessionX11Request.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketSessionX11Request.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketSessionX11Request.java,v 1.2 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class PacketSessionX11Request {\r\n    public int recipientChannelID;\r\n    public boolean wantReply;\r\n    public boolean singleConnection;\r\n    byte[] payload;\r\n    String x11AuthenticationProtocol;\r\n    String x11AuthenticationCookie;\r\n    int x11ScreenNumber;\r\n\r\n    public PacketSessionX11Request(int recipientChannelID, boolean wantReply, boolean singleConnection,\r\n                                   String x11AuthenticationProtocol, String x11AuthenticationCookie, int x11ScreenNumber) {\r\n        this.recipientChannelID = recipientChannelID;\r\n        this.wantReply = wantReply;\r\n\r\n        this.singleConnection = singleConnection;\r\n        this.x11AuthenticationProtocol = x11AuthenticationProtocol;\r\n        this.x11AuthenticationCookie = x11AuthenticationCookie;\r\n        this.x11ScreenNumber = x11ScreenNumber;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_CHANNEL_REQUEST);\r\n            tw.writeUINT32(recipientChannelID);\r\n            tw.writeString(\"x11-req\");\r\n            tw.writeBoolean(wantReply);\r\n\r\n            tw.writeBoolean(singleConnection);\r\n            tw.writeString(x11AuthenticationProtocol);\r\n            tw.writeString(x11AuthenticationCookie);\r\n            tw.writeUINT32(x11ScreenNumber);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthBanner.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthBanner.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthBanner.java,v 1.2 2005/08/24 17:54:08 cplattne Exp $\r\n */\r\npublic class PacketUserauthBanner {\r\n    byte[] payload;\r\n\r\n    String message;\r\n    String language;\r\n\r\n    public PacketUserauthBanner(String message, String language) {\r\n        this.message = message;\r\n        this.language = language;\r\n    }\r\n\r\n    public PacketUserauthBanner(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_BANNER)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_BANNER! (\" + packet_type + \")\");\r\n\r\n        message = tr.readString(\"UTF-8\");\r\n        language = tr.readString();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_USERAUTH_REQUEST packet!\");\r\n    }\r\n\r\n    public String getBanner() {\r\n        return message;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_BANNER);\r\n            tw.writeString(message);\r\n            tw.writeString(language);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthFailure.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthBanner.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthFailure.java,v 1.3 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketUserauthFailure {\r\n    byte[] payload;\r\n\r\n    String[] authThatCanContinue;\r\n    boolean partialSuccess;\r\n\r\n    public PacketUserauthFailure(String[] authThatCanContinue, boolean partialSuccess) {\r\n        this.authThatCanContinue = authThatCanContinue;\r\n        this.partialSuccess = partialSuccess;\r\n    }\r\n\r\n    public PacketUserauthFailure(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_FAILURE)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_FAILURE! (\" + packet_type + \")\");\r\n\r\n        authThatCanContinue = tr.readNameList();\r\n        partialSuccess = tr.readBoolean();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_USERAUTH_FAILURE packet!\");\r\n    }\r\n\r\n    public String[] getAuthThatCanContinue() {\r\n        return authThatCanContinue;\r\n    }\r\n\r\n    public boolean isPartialSuccess() {\r\n        return partialSuccess;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthInfoRequest.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthInfoRequest.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthInfoRequest.java,v 1.2 2005/07/21 15:28:51 cplattne Exp $\r\n */\r\npublic class PacketUserauthInfoRequest {\r\n    byte[] payload;\r\n\r\n    String name;\r\n    String instruction;\r\n    String languageTag;\r\n    int numPrompts;\r\n\r\n    String prompt[];\r\n    boolean echo[];\r\n\r\n    public PacketUserauthInfoRequest(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_INFO_REQUEST)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_INFO_REQUEST! (\" + packet_type + \")\");\r\n\r\n        name = tr.readString();\r\n        instruction = tr.readString();\r\n        languageTag = tr.readString();\r\n\r\n        numPrompts = tr.readUINT32();\r\n\r\n        prompt = new String[numPrompts];\r\n        echo = new boolean[numPrompts];\r\n\r\n        for (int i = 0; i < numPrompts; i++) {\r\n            prompt[i] = tr.readString();\r\n            echo[i] = tr.readBoolean();\r\n        }\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_USERAUTH_INFO_REQUEST packet!\");\r\n    }\r\n\r\n    public boolean[] getEcho() {\r\n        return echo;\r\n    }\r\n\r\n    public String getInstruction() {\r\n        return instruction;\r\n    }\r\n\r\n    public String getLanguageTag() {\r\n        return languageTag;\r\n    }\r\n\r\n    public String getName() {\r\n        return name;\r\n    }\r\n\r\n    public int getNumPrompts() {\r\n        return numPrompts;\r\n    }\r\n\r\n    public String[] getPrompt() {\r\n        return prompt;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthInfoResponse.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketUserauthInfoResponse.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthInfoResponse.java,v 1.3 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketUserauthInfoResponse {\r\n    byte[] payload;\r\n\r\n    String[] responses;\r\n\r\n    public PacketUserauthInfoResponse(String[] responses) {\r\n        this.responses = responses;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_INFO_RESPONSE);\r\n            tw.writeUINT32(responses.length);\r\n            for (int i = 0; i < responses.length; i++)\r\n                tw.writeString(responses[i]);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthRequestInteractive.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * PacketUserauthRequestInteractive.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthRequestInteractive.java,v 1.3 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketUserauthRequestInteractive {\r\n    byte[] payload;\r\n\r\n    String userName;\r\n    String serviceName;\r\n    String[] submethods;\r\n\r\n    public PacketUserauthRequestInteractive(String serviceName, String user, String[] submethods) {\r\n        this.serviceName = serviceName;\r\n        this.userName = user;\r\n        this.submethods = submethods;\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n            tw.writeString(userName);\r\n            tw.writeString(serviceName);\r\n            tw.writeString(\"keyboard-interactive\");\r\n            tw.writeString(\"\"); // draft-ietf-secsh-newmodes-04.txt says that\r\n            // the language tag should be empty.\r\n            tw.writeNameList(submethods);\r\n\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthRequestNone.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthRequestPassword.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthRequestNone.java,v 1.2 2005/08/24 17:54:08 cplattne Exp $\r\n */\r\npublic class PacketUserauthRequestNone {\r\n    byte[] payload;\r\n\r\n    String userName;\r\n    String serviceName;\r\n\r\n    public PacketUserauthRequestNone(String serviceName, String user) {\r\n        this.serviceName = serviceName;\r\n        this.userName = user;\r\n    }\r\n\r\n    public PacketUserauthRequestNone(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_REQUEST! (\" + packet_type + \")\");\r\n\r\n        userName = tr.readString();\r\n        serviceName = tr.readString();\r\n\r\n        String method = tr.readString();\r\n\r\n        if (method.equals(\"none\") == false)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_REQUEST with type none!\");\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_USERAUTH_REQUEST packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n            tw.writeString(userName);\r\n            tw.writeString(serviceName);\r\n            tw.writeString(\"none\");\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthRequestPassword.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthRequestPassword.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthRequestPassword.java,v 1.3 2005/08/24 17:54:09 cplattne Exp $\r\n */\r\npublic class PacketUserauthRequestPassword {\r\n    byte[] payload;\r\n\r\n    String userName;\r\n    String serviceName;\r\n    String password;\r\n\r\n    public PacketUserauthRequestPassword(String serviceName, String user, String pass) {\r\n        this.serviceName = serviceName;\r\n        this.userName = user;\r\n        this.password = pass;\r\n    }\r\n\r\n    public PacketUserauthRequestPassword(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_REQUEST! (\" + packet_type + \")\");\r\n\r\n        userName = tr.readString();\r\n        serviceName = tr.readString();\r\n\r\n        String method = tr.readString();\r\n\r\n        if (method.equals(\"password\") == false)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_REQUEST with type password!\");\r\n\r\n\t\t/* ... */\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in SSH_MSG_USERAUTH_REQUEST packet!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n            tw.writeString(userName);\r\n            tw.writeString(serviceName);\r\n            tw.writeString(\"password\");\r\n            tw.writeBoolean(false);\r\n            tw.writeString(password);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/PacketUserauthRequestPublicKey.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * PacketUserauthRequestPublicKey.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: PacketUserauthRequestPublicKey.java,v 1.2 2005/08/24 17:54:08 cplattne Exp $\r\n */\r\npublic class PacketUserauthRequestPublicKey {\r\n    byte[] payload;\r\n\r\n    String userName;\r\n    String serviceName;\r\n    String password;\r\n    String pkAlgoName;\r\n    byte[] pk;\r\n    byte[] sig;\r\n\r\n    public PacketUserauthRequestPublicKey(String serviceName, String user,\r\n                                          String pkAlgorithmName, byte[] pk, byte[] sig) {\r\n        this.serviceName = serviceName;\r\n        this.userName = user;\r\n        this.pkAlgoName = pkAlgorithmName;\r\n        this.pk = pk;\r\n        this.sig = sig;\r\n    }\r\n\r\n    public PacketUserauthRequestPublicKey(byte payload[], int off, int len) throws IOException {\r\n        this.payload = new byte[len];\r\n        System.arraycopy(payload, off, this.payload, 0, len);\r\n\r\n        TypesReader tr = new TypesReader(payload, off, len);\r\n\r\n        int packet_type = tr.readByte();\r\n\r\n        if (packet_type != Packets.SSH_MSG_USERAUTH_REQUEST)\r\n            throw new IOException(\"This is not a SSH_MSG_USERAUTH_REQUEST! (\"\r\n                    + packet_type + \")\");\r\n\r\n        throw new IOException(\"Not implemented!\");\r\n    }\r\n\r\n    public byte[] getPayload() {\r\n        if (payload == null) {\r\n            TypesWriter tw = new TypesWriter();\r\n            tw.writeByte(Packets.SSH_MSG_USERAUTH_REQUEST);\r\n            tw.writeString(userName);\r\n            tw.writeString(serviceName);\r\n            tw.writeString(\"publickey\");\r\n            tw.writeBoolean(true);\r\n            tw.writeString(pkAlgoName);\r\n            tw.writeString(pk, 0, pk.length);\r\n            tw.writeString(sig, 0, sig.length);\r\n            payload = tw.getBytes();\r\n        }\r\n        return payload;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/Packets.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\n/**\r\n * Packets.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Packets.java,v 1.6 2006/09/20 12:51:37 cplattne Exp $\r\n */\r\npublic class Packets {\r\n    public static final int SSH_MSG_DISCONNECT = 1;\r\n    public static final int SSH_MSG_IGNORE = 2;\r\n    public static final int SSH_MSG_UNIMPLEMENTED = 3;\r\n    public static final int SSH_MSG_DEBUG = 4;\r\n    public static final int SSH_MSG_SERVICE_REQUEST = 5;\r\n    public static final int SSH_MSG_SERVICE_ACCEPT = 6;\r\n\r\n    public static final int SSH_MSG_KEXINIT = 20;\r\n    public static final int SSH_MSG_NEWKEYS = 21;\r\n\r\n    public static final int SSH_MSG_KEXDH_INIT = 30;\r\n    public static final int SSH_MSG_KEXDH_REPLY = 31;\r\n\r\n    public static final int SSH_MSG_KEX_DH_GEX_REQUEST_OLD = 30;\r\n    public static final int SSH_MSG_KEX_DH_GEX_REQUEST = 34;\r\n    public static final int SSH_MSG_KEX_DH_GEX_GROUP = 31;\r\n    public static final int SSH_MSG_KEX_DH_GEX_INIT = 32;\r\n    public static final int SSH_MSG_KEX_DH_GEX_REPLY = 33;\r\n\r\n    public static final int SSH_MSG_USERAUTH_REQUEST = 50;\r\n    public static final int SSH_MSG_USERAUTH_FAILURE = 51;\r\n    public static final int SSH_MSG_USERAUTH_SUCCESS = 52;\r\n    public static final int SSH_MSG_USERAUTH_BANNER = 53;\r\n    public static final int SSH_MSG_USERAUTH_INFO_REQUEST = 60;\r\n    public static final int SSH_MSG_USERAUTH_INFO_RESPONSE = 61;\r\n\r\n    public static final int SSH_MSG_GLOBAL_REQUEST = 80;\r\n    public static final int SSH_MSG_REQUEST_SUCCESS = 81;\r\n    public static final int SSH_MSG_REQUEST_FAILURE = 82;\r\n\r\n    public static final int SSH_MSG_CHANNEL_OPEN = 90;\r\n    public static final int SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 91;\r\n    public static final int SSH_MSG_CHANNEL_OPEN_FAILURE = 92;\r\n    public static final int SSH_MSG_CHANNEL_WINDOW_ADJUST = 93;\r\n    public static final int SSH_MSG_CHANNEL_DATA = 94;\r\n    public static final int SSH_MSG_CHANNEL_EXTENDED_DATA = 95;\r\n    public static final int SSH_MSG_CHANNEL_EOF = 96;\r\n    public static final int SSH_MSG_CHANNEL_CLOSE = 97;\r\n    public static final int SSH_MSG_CHANNEL_REQUEST = 98;\r\n    public static final int SSH_MSG_CHANNEL_SUCCESS = 99;\r\n    public static final int SSH_MSG_CHANNEL_FAILURE = 100;\r\n\r\n    public static final int SSH_EXTENDED_DATA_STDERR = 1;\r\n\r\n    public static final int SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT = 1;\r\n    public static final int SSH_DISCONNECT_PROTOCOL_ERROR = 2;\r\n    public static final int SSH_DISCONNECT_KEY_EXCHANGE_FAILED = 3;\r\n    public static final int SSH_DISCONNECT_RESERVED = 4;\r\n    public static final int SSH_DISCONNECT_MAC_ERROR = 5;\r\n    public static final int SSH_DISCONNECT_COMPRESSION_ERROR = 6;\r\n    public static final int SSH_DISCONNECT_SERVICE_NOT_AVAILABLE = 7;\r\n    public static final int SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED = 8;\r\n    public static final int SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE = 9;\r\n    public static final int SSH_DISCONNECT_CONNECTION_LOST = 10;\r\n    public static final int SSH_DISCONNECT_BY_APPLICATION = 11;\r\n    public static final int SSH_DISCONNECT_TOO_MANY_CONNECTIONS = 12;\r\n    public static final int SSH_DISCONNECT_AUTH_CANCELLED_BY_USER = 13;\r\n    public static final int SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE = 14;\r\n    public static final int SSH_DISCONNECT_ILLEGAL_USER_NAME = 15;\r\n\r\n    public static final int SSH_OPEN_ADMINISTRATIVELY_PROHIBITED = 1;\r\n    public static final int SSH_OPEN_CONNECT_FAILED = 2;\r\n    public static final int SSH_OPEN_UNKNOWN_CHANNEL_TYPE = 3;\r\n    public static final int SSH_OPEN_RESOURCE_SHORTAGE = 4;\r\n\r\n    private static final String[] reverseNames = new String[101];\r\n\r\n    static {\r\n        reverseNames[1] = \"SSH_MSG_DISCONNECT\";\r\n        reverseNames[2] = \"SSH_MSG_IGNORE\";\r\n        reverseNames[3] = \"SSH_MSG_UNIMPLEMENTED\";\r\n        reverseNames[4] = \"SSH_MSG_DEBUG\";\r\n        reverseNames[5] = \"SSH_MSG_SERVICE_REQUEST\";\r\n        reverseNames[6] = \"SSH_MSG_SERVICE_ACCEPT\";\r\n\r\n        reverseNames[20] = \"SSH_MSG_KEXINIT\";\r\n        reverseNames[21] = \"SSH_MSG_NEWKEYS\";\r\n\r\n        reverseNames[30] = \"SSH_MSG_KEXDH_INIT\";\r\n        reverseNames[31] = \"SSH_MSG_KEXDH_REPLY/SSH_MSG_KEX_DH_GEX_GROUP\";\r\n        reverseNames[32] = \"SSH_MSG_KEX_DH_GEX_INIT\";\r\n        reverseNames[33] = \"SSH_MSG_KEX_DH_GEX_REPLY\";\r\n        reverseNames[34] = \"SSH_MSG_KEX_DH_GEX_REQUEST\";\r\n\r\n        reverseNames[50] = \"SSH_MSG_USERAUTH_REQUEST\";\r\n        reverseNames[51] = \"SSH_MSG_USERAUTH_FAILURE\";\r\n        reverseNames[52] = \"SSH_MSG_USERAUTH_SUCCESS\";\r\n        reverseNames[53] = \"SSH_MSG_USERAUTH_BANNER\";\r\n\r\n        reverseNames[60] = \"SSH_MSG_USERAUTH_INFO_REQUEST\";\r\n        reverseNames[61] = \"SSH_MSG_USERAUTH_INFO_RESPONSE\";\r\n\r\n        reverseNames[80] = \"SSH_MSG_GLOBAL_REQUEST\";\r\n        reverseNames[81] = \"SSH_MSG_REQUEST_SUCCESS\";\r\n        reverseNames[82] = \"SSH_MSG_REQUEST_FAILURE\";\r\n\r\n        reverseNames[90] = \"SSH_MSG_CHANNEL_OPEN\";\r\n        reverseNames[91] = \"SSH_MSG_CHANNEL_OPEN_CONFIRMATION\";\r\n        reverseNames[92] = \"SSH_MSG_CHANNEL_OPEN_FAILURE\";\r\n        reverseNames[93] = \"SSH_MSG_CHANNEL_WINDOW_ADJUST\";\r\n        reverseNames[94] = \"SSH_MSG_CHANNEL_DATA\";\r\n        reverseNames[95] = \"SSH_MSG_CHANNEL_EXTENDED_DATA\";\r\n        reverseNames[96] = \"SSH_MSG_CHANNEL_EOF\";\r\n        reverseNames[97] = \"SSH_MSG_CHANNEL_CLOSE\";\r\n        reverseNames[98] = \"SSH_MSG_CHANNEL_REQUEST\";\r\n        reverseNames[99] = \"SSH_MSG_CHANNEL_SUCCESS\";\r\n        reverseNames[100] = \"SSH_MSG_CHANNEL_FAILURE\";\r\n    }\r\n\r\n    public static final String getMessageName(int type) {\r\n        String res = null;\r\n\r\n        if ((type >= 0) && (type < reverseNames.length)) {\r\n            res = reverseNames[type];\r\n        }\r\n\r\n        return (res == null) ? (\"UNKNOWN MSG \" + type) : res;\r\n    }\r\n\r\n    //\tpublic static final void debug(String tag, byte[] msg)\r\n    //\t{\r\n    //\t\tSystem.err.println(tag + \" Type: \" + msg[0] + \", LEN: \" + msg.length);\r\n    //\r\n    //\t\tfor (int i = 0; i < msg.length; i++)\r\n    //\t\t{\r\n    //\t\t\tif (((msg[i] >= 'a') && (msg[i] <= 'z')) || ((msg[i] >= 'A') && (msg[i] <= 'Z'))\r\n    //\t\t\t\t\t|| ((msg[i] >= '0') && (msg[i] <= '9')) || (msg[i] == ' '))\r\n    //\t\t\t\tSystem.err.print((char) msg[i]);\r\n    //\t\t\telse\r\n    //\t\t\t\tSystem.err.print(\".\");\r\n    //\t\t}\r\n    //\t\tSystem.err.println();\r\n    //\t\tSystem.err.flush();\r\n    //\t}\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/TypesReader.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport ch.ethz.ssh2.util.Tokenizer;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * TypesReader.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: TypesReader.java,v 1.6 2006/08/31 20:04:29 cplattne Exp $\r\n */\r\npublic class TypesReader {\r\n    byte[] arr;\r\n    int pos = 0;\r\n    int max = 0;\r\n\r\n    public TypesReader(byte[] arr) {\r\n        this.arr = arr;\r\n        pos = 0;\r\n        max = arr.length;\r\n    }\r\n\r\n    public TypesReader(byte[] arr, int off) {\r\n        this.arr = arr;\r\n        this.pos = off;\r\n        this.max = arr.length;\r\n\r\n        if ((pos < 0) || (pos > arr.length))\r\n            throw new IllegalArgumentException(\"Illegal offset.\");\r\n    }\r\n\r\n    public TypesReader(byte[] arr, int off, int len) {\r\n        this.arr = arr;\r\n        this.pos = off;\r\n        this.max = off + len;\r\n\r\n        if ((pos < 0) || (pos > arr.length))\r\n            throw new IllegalArgumentException(\"Illegal offset.\");\r\n\r\n        if ((max < 0) || (max > arr.length))\r\n            throw new IllegalArgumentException(\"Illegal length.\");\r\n    }\r\n\r\n    public int readByte() throws IOException {\r\n        if (pos >= max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        return (arr[pos++] & 0xff);\r\n    }\r\n\r\n    public byte[] readBytes(int len) throws IOException {\r\n        if ((pos + len) > max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        byte[] res = new byte[len];\r\n\r\n        System.arraycopy(arr, pos, res, 0, len);\r\n        pos += len;\r\n\r\n        return res;\r\n    }\r\n\r\n    public void readBytes(byte[] dst, int off, int len) throws IOException {\r\n        if ((pos + len) > max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        System.arraycopy(arr, pos, dst, off, len);\r\n        pos += len;\r\n    }\r\n\r\n    public boolean readBoolean() throws IOException {\r\n        if (pos >= max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        return (arr[pos++] != 0);\r\n    }\r\n\r\n    public int readUINT32() throws IOException {\r\n        if ((pos + 4) > max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        return ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)\r\n                | (arr[pos++] & 0xff);\r\n    }\r\n\r\n    public long readUINT64() throws IOException {\r\n        if ((pos + 8) > max)\r\n            throw new IOException(\"Packet too short.\");\r\n\r\n        long high = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)\r\n                | (arr[pos++] & 0xff); /* sign extension may take place - will be shifted away =) */\r\n\r\n        long low = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)\r\n                | (arr[pos++] & 0xff); /* sign extension may take place - handle below */\r\n\r\n        return (high << 32) | (low & 0xffffffffl); /* see Java language spec (15.22.1, 5.6.2) */\r\n    }\r\n\r\n    public BigInteger readMPINT() throws IOException {\r\n        BigInteger b;\r\n\r\n        byte raw[] = readByteString();\r\n\r\n        if (raw.length == 0)\r\n            b = BigInteger.ZERO;\r\n        else\r\n            b = new BigInteger(raw);\r\n\r\n        return b;\r\n    }\r\n\r\n    public byte[] readByteString() throws IOException {\r\n        int len = readUINT32();\r\n\r\n        if ((len + pos) > max)\r\n            throw new IOException(\"Malformed SSH byte string.\");\r\n\r\n        byte[] res = new byte[len];\r\n        System.arraycopy(arr, pos, res, 0, len);\r\n        pos += len;\r\n        return res;\r\n    }\r\n\r\n    public String readString(String charsetName) throws IOException {\r\n        int len = readUINT32();\r\n\r\n        if ((len + pos) > max)\r\n            throw new IOException(\"Malformed SSH string.\");\r\n\r\n        String res = (charsetName == null) ? new String(arr, pos, len) : new String(arr, pos, len, charsetName);\r\n        pos += len;\r\n\r\n        return res;\r\n    }\r\n\r\n    public String readString() throws IOException {\r\n        int len = readUINT32();\r\n\r\n        if ((len + pos) > max)\r\n            throw new IOException(\"Malformed SSH string.\");\r\n\r\n        String res = new String(arr, pos, len);\r\n        pos += len;\r\n\r\n        return res;\r\n    }\r\n\r\n    public String[] readNameList() throws IOException {\r\n        return Tokenizer.parseTokens(readString(), ',');\r\n    }\r\n\r\n    public int remain() {\r\n        return max - pos;\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/packets/TypesWriter.java",
    "content": "package ch.ethz.ssh2.packets;\r\n\r\nimport java.io.UnsupportedEncodingException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * TypesWriter.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: TypesWriter.java,v 1.6 2006/08/31 20:04:29 cplattne Exp $\r\n */\r\npublic class TypesWriter {\r\n    byte arr[];\r\n    int pos;\r\n\r\n    public TypesWriter() {\r\n        arr = new byte[256];\r\n        pos = 0;\r\n    }\r\n\r\n    private void resize(int len) {\r\n        byte new_arr[] = new byte[len];\r\n        System.arraycopy(arr, 0, new_arr, 0, arr.length);\r\n        arr = new_arr;\r\n    }\r\n\r\n    public int length() {\r\n        return pos;\r\n    }\r\n\r\n    public byte[] getBytes() {\r\n        byte[] dst = new byte[pos];\r\n        System.arraycopy(arr, 0, dst, 0, pos);\r\n        return dst;\r\n    }\r\n\r\n    public void getBytes(byte dst[]) {\r\n        System.arraycopy(arr, 0, dst, 0, pos);\r\n    }\r\n\r\n    public void writeUINT32(int val, int off) {\r\n        if ((off + 4) > arr.length)\r\n            resize(off + 32);\r\n\r\n        arr[off++] = (byte) (val >> 24);\r\n        arr[off++] = (byte) (val >> 16);\r\n        arr[off++] = (byte) (val >> 8);\r\n        arr[off++] = (byte) val;\r\n    }\r\n\r\n    public void writeUINT32(int val) {\r\n        writeUINT32(val, pos);\r\n        pos += 4;\r\n    }\r\n\r\n    public void writeUINT64(long val) {\r\n        if ((pos + 8) > arr.length)\r\n            resize(arr.length + 32);\r\n\r\n        arr[pos++] = (byte) (val >> 56);\r\n        arr[pos++] = (byte) (val >> 48);\r\n        arr[pos++] = (byte) (val >> 40);\r\n        arr[pos++] = (byte) (val >> 32);\r\n        arr[pos++] = (byte) (val >> 24);\r\n        arr[pos++] = (byte) (val >> 16);\r\n        arr[pos++] = (byte) (val >> 8);\r\n        arr[pos++] = (byte) val;\r\n    }\r\n\r\n    public void writeBoolean(boolean v) {\r\n        if ((pos + 1) > arr.length)\r\n            resize(arr.length + 32);\r\n\r\n        arr[pos++] = v ? (byte) 1 : (byte) 0;\r\n    }\r\n\r\n    public void writeByte(int v, int off) {\r\n        if ((off + 1) > arr.length)\r\n            resize(off + 32);\r\n\r\n        arr[off] = (byte) v;\r\n    }\r\n\r\n    public void writeByte(int v) {\r\n        writeByte(v, pos);\r\n        pos++;\r\n    }\r\n\r\n    public void writeMPInt(BigInteger b) {\r\n        byte raw[] = b.toByteArray();\r\n\r\n        if ((raw.length == 1) && (raw[0] == 0))\r\n            writeUINT32(0); /* String with zero bytes of data */\r\n        else\r\n            writeString(raw, 0, raw.length);\r\n    }\r\n\r\n    public void writeBytes(byte[] buff) {\r\n        writeBytes(buff, 0, buff.length);\r\n    }\r\n\r\n    public void writeBytes(byte[] buff, int off, int len) {\r\n        if ((pos + len) > arr.length)\r\n            resize(arr.length + len + 32);\r\n\r\n        System.arraycopy(buff, off, arr, pos, len);\r\n        pos += len;\r\n    }\r\n\r\n    public void writeString(byte[] buff, int off, int len) {\r\n        writeUINT32(len);\r\n        writeBytes(buff, off, len);\r\n    }\r\n\r\n    public void writeString(String v) {\r\n        byte[] b = v.getBytes();\r\n\r\n        writeUINT32(b.length);\r\n        writeBytes(b, 0, b.length);\r\n    }\r\n\r\n    public void writeString(String v, String charsetName) throws UnsupportedEncodingException {\r\n        byte[] b = (charsetName == null) ? v.getBytes() : v.getBytes(charsetName);\r\n\r\n        writeUINT32(b.length);\r\n        writeBytes(b, 0, b.length);\r\n    }\r\n\r\n    public void writeNameList(String v[]) {\r\n        StringBuffer sb = new StringBuffer();\r\n        for (int i = 0; i < v.length; i++) {\r\n            if (i > 0)\r\n                sb.append(',');\r\n            sb.append(v[i]);\r\n        }\r\n        writeString(sb.toString());\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/AttrTextHints.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * Values for the 'text-hint' field in the SFTP ATTRS data type.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AttrTextHints.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class AttrTextHints {\r\n    /**\r\n     * The server knows the file is a text file, and should be opened\r\n     * using the SSH_FXF_ACCESS_TEXT_MODE flag.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_KNOWN_TEXT = 0x00;\r\n\r\n    /**\r\n     * The server has applied a heuristic or other mechanism and\r\n     * believes that the file should be opened with the\r\n     * SSH_FXF_ACCESS_TEXT_MODE flag.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_GUESSED_TEXT = 0x01;\r\n\r\n    /**\r\n     * The server knows the file has binary content.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_KNOWN_BINARY = 0x02;\r\n\r\n    /**\r\n     * The server has applied a heuristic or other mechanism and\r\n     * believes has binary content, and should not be opened with the\r\n     * SSH_FXF_ACCESS_TEXT_MODE flag.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_GUESSED_BINARY = 0x03;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/AttribBits.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * SFTP Attribute Bits for the \"attrib-bits\" and \"attrib-bits-valid\" fields\r\n * of the SFTP ATTR data type.\r\n * <p>\r\n * Yes, these are the \"attrib-bits\", even though they have \"_FLAGS_\" in\r\n * their name. Don't ask - I did not invent it.\r\n * <p>\r\n * \"<i>These fields, taken together, reflect various attributes of the file\r\n * or directory, on the server. Bits not set in 'attrib-bits-valid' MUST be\r\n * ignored in the 'attrib-bits' field.  This allows both the server and the\r\n * client to communicate only the bits it knows about without inadvertently\r\n * twiddling bits they don't understand.</i>\"\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AttribBits.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class AttribBits {\r\n    /**\r\n     * Advisory, read-only bit. This bit is not part of the access\r\n     * control information on the file, but is rather an advisory field\r\n     * indicating that the file should not be written.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_READONLY = 0x00000001;\r\n\r\n    /**\r\n     * The file is part of the operating system.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_SYSTEM = 0x00000002;\r\n\r\n    /**\r\n     * File SHOULD NOT be shown to user unless specifically requested.\r\n     * For example, most UNIX systems SHOULD set this bit if the filename\r\n     * begins with a 'period'. This bit may be read-only (see section 5.4 of\r\n     * the SFTP standard draft). Most UNIX systems will not allow this to be\r\n     * changed.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_HIDDEN = 0x00000004;\r\n\r\n    /**\r\n     * This attribute applies only to directories. This attribute is\r\n     * always read-only, and cannot be modified. This attribute means\r\n     * that files and directory names in this directory should be compared\r\n     * without regard to case.\r\n     * <p>\r\n     * It is recommended that where possible, the server's filesystem be\r\n     * allowed to do comparisons. For example, if a client wished to prompt\r\n     * a user before overwriting a file, it should not compare the new name\r\n     * with the previously retrieved list of names in the directory. Rather,\r\n     * it should first try to create the new file by specifying\r\n     * SSH_FXF_CREATE_NEW flag. Then, if this fails and returns\r\n     * SSH_FX_FILE_ALREADY_EXISTS, it should prompt the user and then retry\r\n     * the create specifying SSH_FXF_CREATE_TRUNCATE.\r\n     * <p>\r\n     * Unless otherwise specified, filenames are assumed to be case sensitive.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE = 0x00000008;\r\n\r\n    /**\r\n     * The file should be included in backup / archive operations.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_ARCHIVE = 0x00000010;\r\n\r\n    /**\r\n     * The file is stored on disk using file-system level transparent\r\n     * encryption. This flag does not affect the file data on the wire\r\n     * (for either READ or WRITE requests.)\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED = 0x00000020;\r\n\r\n    /**\r\n     * The file is stored on disk using file-system level transparent\r\n     * compression. This flag does not affect the file data on the wire.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_COMPRESSED = 0x00000040;\r\n\r\n    /**\r\n     * The file is a sparse file; this means that file blocks that have\r\n     * not been explicitly written are not stored on disk. For example, if\r\n     * a client writes a buffer at 10 M from the beginning of the file,\r\n     * the blocks between the previous EOF marker and the 10 M offset would\r\n     * not consume physical disk space.\r\n     * <p>\r\n     * Some servers may store all files as sparse files, in which case\r\n     * this bit will be unconditionally set. Other servers may not have\r\n     * a mechanism for determining if the file is sparse, and so the file\r\n     * MAY be stored sparse even if this flag is not set.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_SPARSE = 0x00000080;\r\n\r\n    /**\r\n     * Opening the file without either the SSH_FXF_ACCESS_APPEND_DATA or\r\n     * the SSH_FXF_ACCESS_APPEND_DATA_ATOMIC flag (see section 8.1.1.3\r\n     * of the SFTP standard draft) MUST result in an\r\n     * SSH_FX_INVALID_PARAMETER error.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY = 0x00000100;\r\n\r\n    /**\r\n     * The file cannot be deleted or renamed, no hard link can be created\r\n     * to this file, and no data can be written to the file.\r\n     * <p>\r\n     * This bit implies a stronger level of protection than\r\n     * SSH_FILEXFER_ATTR_FLAGS_READONLY, the file permission mask or ACLs.\r\n     * Typically even the superuser cannot write to immutable files, and\r\n     * only the superuser can set or remove the bit.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE = 0x00000200;\r\n\r\n    /**\r\n     * When the file is modified, the changes are written synchronously\r\n     * to the disk.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_SYNC = 0x00000400;\r\n\r\n    /**\r\n     * The server MAY include this bit in a directory listing or realpath\r\n     * response. It indicates there was a failure in the translation to UTF-8.\r\n     * If this flag is included, the server SHOULD also include the\r\n     * UNTRANSLATED_NAME attribute.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_FLAGS_TRANSLATION_ERR = 0x00000800;\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/AttribFlags.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * Attribute Flags. The 'valid-attribute-flags' field in\r\n * the SFTP ATTRS data type specifies which of the fields are actually present.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AttribFlags.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class AttribFlags {\r\n    /**\r\n     * Indicates that the 'allocation-size' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;\r\n\r\n    /**\r\n     * Protocol version 6:\r\n     * 0x00000002 was used in a previous version of this protocol.\r\n     * It is now a reserved value and MUST NOT appear in the mask.\r\n     * Some future version of this protocol may reuse this value.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_V3_UIDGID = 0x00000002;\r\n\r\n    /**\r\n     * Indicates that the 'permissions' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;\r\n\r\n    /**\r\n     * Indicates that the 'atime' and 'mtime' field are present\r\n     * (protocol v3).\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_V3_ACMODTIME = 0x00000008;\r\n\r\n    /**\r\n     * Indicates that the 'atime' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008;\r\n\r\n    /**\r\n     * Indicates that the 'createtime' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010;\r\n\r\n    /**\r\n     * Indicates that the 'mtime' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020;\r\n\r\n    /**\r\n     * Indicates that the 'acl' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040;\r\n\r\n    /**\r\n     * Indicates that the 'owner' and 'group' fields are present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080;\r\n\r\n    /**\r\n     * Indicates that additionally to the 'atime', 'createtime',\r\n     * 'mtime' and 'ctime' fields (if present), there is also\r\n     * 'atime-nseconds', 'createtime-nseconds',  'mtime-nseconds'\r\n     * and 'ctime-nseconds'.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100;\r\n\r\n    /**\r\n     * Indicates that the 'attrib-bits' and 'attrib-bits-valid'\r\n     * fields are present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200;\r\n\r\n    /**\r\n     * Indicates that the 'allocation-size' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400;\r\n\r\n    /**\r\n     * Indicates that the 'text-hint' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800;\r\n\r\n    /**\r\n     * Indicates that the 'mime-type' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000;\r\n\r\n    /**\r\n     * Indicates that the 'link-count' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000;\r\n\r\n    /**\r\n     * Indicates that the 'untranslated-name' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000;\r\n\r\n    /**\r\n     * Indicates that the 'ctime' field is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000;\r\n\r\n    /**\r\n     * Indicates that the 'extended-count' field (and probablby some\r\n     * 'extensions') is present.\r\n     */\r\n    public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/AttribPermissions.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * Permissions for the 'permissions' field in the SFTP ATTRS data type.\r\n * <p>\r\n * \"<i>The 'permissions' field contains a bit mask specifying file permissions.\r\n * These permissions correspond to the st_mode field of the stat structure\r\n * defined by POSIX [IEEE.1003-1.1996].</i>\"\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AttribPermissions.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class AttribPermissions {\r\n    /* Octal values! */\r\n\r\n    public static final int S_IRUSR = 0400;\r\n    public static final int S_IWUSR = 0200;\r\n    public static final int S_IXUSR = 0100;\r\n    public static final int S_IRGRP = 0040;\r\n    public static final int S_IWGRP = 0020;\r\n    public static final int S_IXGRP = 0010;\r\n    public static final int S_IROTH = 0004;\r\n    public static final int S_IWOTH = 0002;\r\n    public static final int S_IXOTH = 0001;\r\n    public static final int S_ISUID = 04000;\r\n    public static final int S_ISGID = 02000;\r\n    public static final int S_ISVTX = 01000;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/AttribTypes.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * Types for the 'type' field in the SFTP ATTRS data type.\r\n * <p>\r\n * \"<i>On a POSIX system, these values would be derived from the mode field\r\n * of the stat structure.  SPECIAL should be used for files that are of\r\n * a known type which cannot be expressed in the protocol. UNKNOWN\r\n * should be used if the type is not known.</i>\"\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: AttribTypes.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class AttribTypes {\r\n    public static final int SSH_FILEXFER_TYPE_REGULAR = 1;\r\n    public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2;\r\n    public static final int SSH_FILEXFER_TYPE_SYMLINK = 3;\r\n    public static final int SSH_FILEXFER_TYPE_SPECIAL = 4;\r\n    public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5;\r\n    public static final int SSH_FILEXFER_TYPE_SOCKET = 6;\r\n    public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7;\r\n    public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8;\r\n    public static final int SSH_FILEXFER_TYPE_FIFO = 9;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/ErrorCodes.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * SFTP Error Codes\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ErrorCodes.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class ErrorCodes {\r\n    public static final int SSH_FX_OK = 0;\r\n    public static final int SSH_FX_EOF = 1;\r\n    public static final int SSH_FX_NO_SUCH_FILE = 2;\r\n    public static final int SSH_FX_PERMISSION_DENIED = 3;\r\n    public static final int SSH_FX_FAILURE = 4;\r\n    public static final int SSH_FX_BAD_MESSAGE = 5;\r\n    public static final int SSH_FX_NO_CONNECTION = 6;\r\n    public static final int SSH_FX_CONNECTION_LOST = 7;\r\n    public static final int SSH_FX_OP_UNSUPPORTED = 8;\r\n    public static final int SSH_FX_INVALID_HANDLE = 9;\r\n    public static final int SSH_FX_NO_SUCH_PATH = 10;\r\n    public static final int SSH_FX_FILE_ALREADY_EXISTS = 11;\r\n    public static final int SSH_FX_WRITE_PROTECT = 12;\r\n    public static final int SSH_FX_NO_MEDIA = 13;\r\n    public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14;\r\n    public static final int SSH_FX_QUOTA_EXCEEDED = 15;\r\n    public static final int SSH_FX_UNKNOWN_PRINCIPAL = 16;\r\n    public static final int SSH_FX_LOCK_CONFLICT = 17;\r\n    public static final int SSH_FX_DIR_NOT_EMPTY = 18;\r\n    public static final int SSH_FX_NOT_A_DIRECTORY = 19;\r\n    public static final int SSH_FX_INVALID_FILENAME = 20;\r\n    public static final int SSH_FX_LINK_LOOP = 21;\r\n    public static final int SSH_FX_CANNOT_DELETE = 22;\r\n    public static final int SSH_FX_INVALID_PARAMETER = 23;\r\n    public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24;\r\n    public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25;\r\n    public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26;\r\n    public static final int SSH_FX_DELETE_PENDING = 27;\r\n    public static final int SSH_FX_FILE_CORRUPT = 28;\r\n\r\n    private static final String[][] messages = {\r\n\r\n            {\"SSH_FX_OK\", \"Indicates successful completion of the operation.\"},\r\n            {\"SSH_FX_EOF\",\r\n                    \"An attempt to read past the end-of-file was made; or, there are no more directory entries to return.\"},\r\n            {\"SSH_FX_NO_SUCH_FILE\", \"A reference was made to a file which does not exist.\"},\r\n            {\"SSH_FX_PERMISSION_DENIED\", \"The user does not have sufficient permissions to perform the operation.\"},\r\n            {\"SSH_FX_FAILURE\", \"An error occured, but no specific error code exists to describe the failure.\"},\r\n            {\"SSH_FX_BAD_MESSAGE\", \"A badly formatted packet or other SFTP protocol incompatibility was detected.\"},\r\n            {\"SSH_FX_NO_CONNECTION\", \"There is no connection to the server.\"},\r\n            {\"SSH_FX_CONNECTION_LOST\", \"The connection to the server was lost.\"},\r\n            {\"SSH_FX_OP_UNSUPPORTED\",\r\n                    \"An attempted operation could not be completed by the server because the server does not support the operation.\"},\r\n            {\"SSH_FX_INVALID_HANDLE\", \"The handle value was invalid.\"},\r\n            {\"SSH_FX_NO_SUCH_PATH\", \"The file path does not exist or is invalid.\"},\r\n            {\"SSH_FX_FILE_ALREADY_EXISTS\", \"The file already exists.\"},\r\n            {\"SSH_FX_WRITE_PROTECT\", \"The file is on read-only media, or the media is write protected.\"},\r\n            {\"SSH_FX_NO_MEDIA\",\r\n                    \"The requested operation cannot be completed because there is no media available in the drive.\"},\r\n            {\"SSH_FX_NO_SPACE_ON_FILESYSTEM\",\r\n                    \"The requested operation cannot be completed because there is no free space on the filesystem.\"},\r\n            {\"SSH_FX_QUOTA_EXCEEDED\",\r\n                    \"The operation cannot be completed because it would exceed the user's storage quota.\"},\r\n            {\r\n                    \"SSH_FX_UNKNOWN_PRINCIPAL\",\r\n                    \"A principal referenced by the request (either the 'owner', 'group', or 'who' field of an ACL), was unknown. The error specific data contains the problematic names.\"},\r\n            {\"SSH_FX_LOCK_CONFLICT\", \"The file could not be opened because it is locked by another process.\"},\r\n            {\"SSH_FX_DIR_NOT_EMPTY\", \"The directory is not empty.\"},\r\n            {\"SSH_FX_NOT_A_DIRECTORY\", \"The specified file is not a directory.\"},\r\n            {\"SSH_FX_INVALID_FILENAME\", \"The filename is not valid.\"},\r\n            {\"SSH_FX_LINK_LOOP\", \"Too many symbolic links encountered.\"},\r\n            {\"SSH_FX_CANNOT_DELETE\",\r\n                    \"The file cannot be deleted. One possible reason is that the advisory READONLY attribute-bit is set.\"},\r\n            {\"SSH_FX_INVALID_PARAMETER\",\r\n                    \"One of the parameters was out of range, or the parameters specified cannot be used together.\"},\r\n            {\"SSH_FX_FILE_IS_A_DIRECTORY\",\r\n                    \"The specifed file was a directory in a context where a directory cannot be used.\"},\r\n            {\"SSH_FX_BYTE_RANGE_LOCK_CONFLICT\",\r\n                    \" A read or write operation failed because another process's mandatory byte-range lock overlaps with the request.\"},\r\n            {\"SSH_FX_BYTE_RANGE_LOCK_REFUSED\", \"A request for a byte range lock was refused.\"},\r\n            {\"SSH_FX_DELETE_PENDING\", \"An operation was attempted on a file for which a delete operation is pending.\"},\r\n            {\"SSH_FX_FILE_CORRUPT\", \"The file is corrupt; an filesystem integrity check should be run.\"}};\r\n\r\n    public static final String[] getDescription(int errorCode) {\r\n        if ((errorCode < 0) || (errorCode >= messages.length))\r\n            return null;\r\n\r\n        return messages[errorCode];\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/OpenFlags.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * SFTP Open Flags.\r\n * <p>\r\n * The following table is provided to assist in mapping POSIX semantics\r\n * to equivalent SFTP file open parameters:\r\n * <p>\r\n * TODO: This comment should be moved to the open method.\r\n * <p>\r\n * <ul>\r\n * <li>O_RDONLY\r\n * <ul><li>desired-access = READ_DATA | READ_ATTRIBUTES</li></ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_WRONLY\r\n * <ul><li>desired-access = WRITE_DATA | WRITE_ATTRIBUTES</li></ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_RDWR\r\n * <ul><li>desired-access = READ_DATA | READ_ATTRIBUTES | WRITE_DATA | WRITE_ATTRIBUTES</li></ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_APPEND\r\n * <ul>\r\n * <li>desired-access = WRITE_DATA | WRITE_ATTRIBUTES | APPEND_DATA</li>\r\n * <li>flags = SSH_FXF_ACCESS_APPEND_DATA and or SSH_FXF_ACCESS_APPEND_DATA_ATOMIC</li>\r\n * </ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_CREAT\r\n * <ul>\r\n * <li>flags = SSH_FXF_OPEN_OR_CREATE</li>\r\n * </ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_TRUNC\r\n * <ul>\r\n * <li>flags = SSH_FXF_TRUNCATE_EXISTING</li>\r\n * </ul>\r\n * </li>\r\n * </ul>\r\n * <ul>\r\n * <li>O_TRUNC|O_CREATE\r\n * <ul>\r\n * <li>flags = SSH_FXF_CREATE_TRUNCATE</li>\r\n * </ul>\r\n * </li>\r\n * </ul>\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: OpenFlags.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class OpenFlags {\r\n    /**\r\n     * Disposition is a 3 bit field that controls how the file is opened.\r\n     * The server MUST support these bits (possible enumaration values:\r\n     * SSH_FXF_CREATE_NEW, SSH_FXF_CREATE_TRUNCATE, SSH_FXF_OPEN_EXISTING,\r\n     * SSH_FXF_OPEN_OR_CREATE or SSH_FXF_TRUNCATE_EXISTING).\r\n     */\r\n    public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007;\r\n\r\n    /**\r\n     * A new file is created; if the file already exists, the server\r\n     * MUST return status SSH_FX_FILE_ALREADY_EXISTS.\r\n     */\r\n    public static final int SSH_FXF_CREATE_NEW = 0x00000000;\r\n\r\n    /**\r\n     * A new file is created; if the file already exists, it is opened\r\n     * and truncated.\r\n     */\r\n    public static final int SSH_FXF_CREATE_TRUNCATE = 0x00000001;\r\n\r\n    /**\r\n     * An existing file is opened.  If the file does not exist, the\r\n     * server MUST return SSH_FX_NO_SUCH_FILE. If a directory in the\r\n     * path does not exist, the server SHOULD return\r\n     * SSH_FX_NO_SUCH_PATH. It is also acceptable if the server\r\n     * returns SSH_FX_NO_SUCH_FILE in this case.\r\n     */\r\n    public static final int SSH_FXF_OPEN_EXISTING = 0x00000002;\r\n\r\n    /**\r\n     * If the file exists, it is opened. If the file does not exist,\r\n     * it is created.\r\n     */\r\n    public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003;\r\n\r\n    /**\r\n     * An existing file is opened and truncated. If the file does not\r\n     * exist, the server MUST return the same error codes as defined\r\n     * for SSH_FXF_OPEN_EXISTING.\r\n     */\r\n    public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004;\r\n\r\n    /**\r\n     * Data is always written at the end of the file. The offset field\r\n     * of the SSH_FXP_WRITE requests are ignored.\r\n     * <p>\r\n     * Data is not required to be appended atomically. This means that\r\n     * if multiple writers attempt to append data simultaneously, data\r\n     * from the first may be lost. However, data MAY be appended\r\n     * atomically.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_APPEND_DATA = 0x00000008;\r\n\r\n    /**\r\n     * Data is always written at the end of the file. The offset field\r\n     * of the SSH_FXP_WRITE requests are ignored.\r\n     * <p>\r\n     * Data MUST be written atomically so that there is no chance that\r\n     * multiple appenders can collide and result in data being lost.\r\n     * <p>\r\n     * If both append flags are specified, the server SHOULD use atomic\r\n     * append if it is available, but SHOULD use non-atomic appends\r\n     * otherwise. The server SHOULD NOT fail the request in this case.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_APPEND_DATA_ATOMIC = 0x00000010;\r\n\r\n    /**\r\n     * Indicates that the server should treat the file as text and\r\n     * convert it to the canonical newline convention in use.\r\n     * (See Determining Server Newline Convention in section 5.3 in the\r\n     * SFTP standard draft).\r\n     * <p>\r\n     * When a file is opened with this flag, the offset field in the read\r\n     * and write functions is ignored.\r\n     * <p>\r\n     * Servers MUST process multiple, parallel reads and writes correctly\r\n     * in this mode.  Naturally, it is permissible for them to do this by\r\n     * serializing the requests.\r\n     * <p>\r\n     * Clients SHOULD use the SSH_FXF_ACCESS_APPEND_DATA flag to append\r\n     * data to a text file rather then using write with a calculated offset.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_TEXT_MODE = 0x00000020;\r\n\r\n    /**\r\n     * The server MUST guarantee that no other handle has been opened\r\n     * with ACE4_READ_DATA access, and that no other handle will be\r\n     * opened with ACE4_READ_DATA access until the client closes the\r\n     * handle. (This MUST apply both to other clients and to other\r\n     * processes on the server.)\r\n     * <p>\r\n     * If there is a conflicting lock the server MUST return\r\n     * SSH_FX_LOCK_CONFLICT.  If the server cannot make the locking\r\n     * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED.\r\n     * <p>\r\n     * Other handles MAY be opened for ACE4_WRITE_DATA or any other\r\n     * combination of accesses, as long as ACE4_READ_DATA is not included\r\n     * in the mask.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_BLOCK_READ = 0x00000040;\r\n\r\n    /**\r\n     * The server MUST guarantee that no other handle has been opened\r\n     * with ACE4_WRITE_DATA or ACE4_APPEND_DATA access, and that no other\r\n     * handle will be opened with ACE4_WRITE_DATA or ACE4_APPEND_DATA\r\n     * access until the client closes the handle. (This MUST apply both\r\n     * to other clients and to other processes on the server.)\r\n     * <p>\r\n     * If there is a conflicting lock the server MUST return\r\n     * SSH_FX_LOCK_CONFLICT. If the server cannot make the locking\r\n     * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED.\r\n     * <p>\r\n     * Other handles MAY be opened for ACE4_READ_DATA or any other\r\n     * combination of accesses, as long as neither ACE4_WRITE_DATA nor\r\n     * ACE4_APPEND_DATA are included in the mask.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_BLOCK_WRITE = 0x00000080;\r\n\r\n    /**\r\n     * The server MUST guarantee that no other handle has been opened\r\n     * with ACE4_DELETE access, opened with the\r\n     * SSH_FXF_ACCESS_DELETE_ON_CLOSE flag set, and that no other handle\r\n     * will be opened with ACE4_DELETE access or with the\r\n     * SSH_FXF_ACCESS_DELETE_ON_CLOSE flag set, and that the file itself\r\n     * is not deleted in any other way until the client closes the handle.\r\n     * <p>\r\n     * If there is a conflicting lock the server MUST return\r\n     * SSH_FX_LOCK_CONFLICT.  If the server cannot make the locking\r\n     * guarantee, it MUST return SSH_FX_OP_UNSUPPORTED.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_BLOCK_DELETE = 0x00000100;\r\n\r\n    /**\r\n     * If this bit is set, the above BLOCK modes are advisory. In advisory\r\n     * mode, only other accesses that specify a BLOCK mode need be\r\n     * considered when determining whether the BLOCK can be granted,\r\n     * and the server need not prevent I/O operations that violate the\r\n     * block mode.\r\n     * <p>\r\n     * The server MAY perform mandatory locking even if the BLOCK_ADVISORY\r\n     * bit is set.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_BLOCK_ADVISORY = 0x00000200;\r\n\r\n    /**\r\n     * If the final component of the path is a symlink, then the open\r\n     * MUST fail, and the error SSH_FX_LINK_LOOP MUST be returned.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_NOFOLLOW = 0x00000400;\r\n\r\n    /**\r\n     * The file should be deleted when the last handle to it is closed.\r\n     * (The last handle may not be an sftp-handle.)  This MAY be emulated\r\n     * by a server if the OS doesn't support it by deleting the file when\r\n     * this handle is closed.\r\n     * <p>\r\n     * It is implementation specific whether the directory entry is\r\n     * removed immediately or when the handle is closed.\r\n     */\r\n    public static final int SSH_FXF_ACCESS_DELETE_ON_CLOSE = 0x00000800;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/sftp/Packet.java",
    "content": "package ch.ethz.ssh2.sftp;\r\n\r\n/**\r\n * SFTP Paket Types\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Packet.java,v 1.2 2006/08/02 12:05:00 cplattne Exp $\r\n */\r\npublic class Packet {\r\n    public static final int SSH_FXP_INIT = 1;\r\n    public static final int SSH_FXP_VERSION = 2;\r\n    public static final int SSH_FXP_OPEN = 3;\r\n    public static final int SSH_FXP_CLOSE = 4;\r\n    public static final int SSH_FXP_READ = 5;\r\n    public static final int SSH_FXP_WRITE = 6;\r\n    public static final int SSH_FXP_LSTAT = 7;\r\n    public static final int SSH_FXP_FSTAT = 8;\r\n    public static final int SSH_FXP_SETSTAT = 9;\r\n    public static final int SSH_FXP_FSETSTAT = 10;\r\n    public static final int SSH_FXP_OPENDIR = 11;\r\n    public static final int SSH_FXP_READDIR = 12;\r\n    public static final int SSH_FXP_REMOVE = 13;\r\n    public static final int SSH_FXP_MKDIR = 14;\r\n    public static final int SSH_FXP_RMDIR = 15;\r\n    public static final int SSH_FXP_REALPATH = 16;\r\n    public static final int SSH_FXP_STAT = 17;\r\n    public static final int SSH_FXP_RENAME = 18;\r\n    public static final int SSH_FXP_READLINK = 19;\r\n    public static final int SSH_FXP_SYMLINK = 20;\r\n\r\n    public static final int SSH_FXP_STATUS = 101;\r\n    public static final int SSH_FXP_HANDLE = 102;\r\n    public static final int SSH_FXP_DATA = 103;\r\n    public static final int SSH_FXP_NAME = 104;\r\n    public static final int SSH_FXP_ATTRS = 105;\r\n\r\n    public static final int SSH_FXP_EXTENDED = 200;\r\n    public static final int SSH_FXP_EXTENDED_REPLY = 201;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/DSAPrivateKey.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * DSAPrivateKey.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DSAPrivateKey.java,v 1.1 2005/05/26 14:53:30 cplattne Exp $\r\n */\r\npublic class DSAPrivateKey {\r\n    private BigInteger p;\r\n    private BigInteger q;\r\n    private BigInteger g;\r\n    private BigInteger x;\r\n    private BigInteger y;\r\n\r\n    public DSAPrivateKey(BigInteger p, BigInteger q, BigInteger g,\r\n                         BigInteger y, BigInteger x) {\r\n        this.p = p;\r\n        this.q = q;\r\n        this.g = g;\r\n        this.y = y;\r\n        this.x = x;\r\n    }\r\n\r\n    public BigInteger getP() {\r\n        return p;\r\n    }\r\n\r\n    public BigInteger getQ() {\r\n        return q;\r\n    }\r\n\r\n    public BigInteger getG() {\r\n        return g;\r\n    }\r\n\r\n    public BigInteger getY() {\r\n        return y;\r\n    }\r\n\r\n    public BigInteger getX() {\r\n        return x;\r\n    }\r\n\r\n    public DSAPublicKey getPublicKey() {\r\n        return new DSAPublicKey(p, q, g, y);\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/DSAPublicKey.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * DSAPublicKey.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DSAPublicKey.java,v 1.1 2005/05/26 14:53:30 cplattne Exp $\r\n */\r\npublic class DSAPublicKey {\r\n    private BigInteger p;\r\n    private BigInteger q;\r\n    private BigInteger g;\r\n    private BigInteger y;\r\n\r\n    public DSAPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y) {\r\n        this.p = p;\r\n        this.q = q;\r\n        this.g = g;\r\n        this.y = y;\r\n    }\r\n\r\n    public BigInteger getP() {\r\n        return p;\r\n    }\r\n\r\n    public BigInteger getQ() {\r\n        return q;\r\n    }\r\n\r\n    public BigInteger getG() {\r\n        return g;\r\n    }\r\n\r\n    public BigInteger getY() {\r\n        return y;\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/DSASHA1Verify.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport ch.ethz.ssh2.crypto.digest.SHA1;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.TypesReader;\r\nimport ch.ethz.ssh2.packets.TypesWriter;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * DSASHA1Verify.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DSASHA1Verify.java,v 1.5 2006/02/14 19:43:16 cplattne Exp $\r\n */\r\npublic class DSASHA1Verify {\r\n    private static final Logger log = Logger.getLogger(DSASHA1Verify.class);\r\n\r\n    public static DSAPublicKey decodeSSHDSAPublicKey(byte[] key) throws IOException {\r\n        TypesReader tr = new TypesReader(key);\r\n\r\n        String key_format = tr.readString();\r\n\r\n        if (key_format.equals(\"ssh-dss\") == false)\r\n            throw new IllegalArgumentException(\"This is not a ssh-dss public key!\");\r\n\r\n        BigInteger p = tr.readMPINT();\r\n        BigInteger q = tr.readMPINT();\r\n        BigInteger g = tr.readMPINT();\r\n        BigInteger y = tr.readMPINT();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in DSA public key!\");\r\n\r\n        return new DSAPublicKey(p, q, g, y);\r\n    }\r\n\r\n    public static byte[] encodeSSHDSAPublicKey(DSAPublicKey pk) throws IOException {\r\n        TypesWriter tw = new TypesWriter();\r\n\r\n        tw.writeString(\"ssh-dss\");\r\n        tw.writeMPInt(pk.getP());\r\n        tw.writeMPInt(pk.getQ());\r\n        tw.writeMPInt(pk.getG());\r\n        tw.writeMPInt(pk.getY());\r\n\r\n        return tw.getBytes();\r\n    }\r\n\r\n    public static byte[] encodeSSHDSASignature(DSASignature ds) {\r\n        TypesWriter tw = new TypesWriter();\r\n\r\n        tw.writeString(\"ssh-dss\");\r\n\r\n        byte[] r = ds.getR().toByteArray();\r\n        byte[] s = ds.getS().toByteArray();\r\n\r\n        byte[] a40 = new byte[40];\r\n\r\n\t\t/* Patch (unsigned) r and s into the target array. */\r\n\r\n        int r_copylen = (r.length < 20) ? r.length : 20;\r\n        int s_copylen = (s.length < 20) ? s.length : 20;\r\n\r\n        System.arraycopy(r, r.length - r_copylen, a40, 20 - r_copylen, r_copylen);\r\n        System.arraycopy(s, s.length - s_copylen, a40, 40 - s_copylen, s_copylen);\r\n\r\n        tw.writeString(a40, 0, 40);\r\n\r\n        return tw.getBytes();\r\n    }\r\n\r\n    public static DSASignature decodeSSHDSASignature(byte[] sig) throws IOException {\r\n        TypesReader tr = new TypesReader(sig);\r\n\r\n        String sig_format = tr.readString();\r\n\r\n        if (sig_format.equals(\"ssh-dss\") == false)\r\n            throw new IOException(\"Peer sent wrong signature format\");\r\n\r\n        byte[] rsArray = tr.readByteString();\r\n\r\n        if (rsArray.length != 40)\r\n            throw new IOException(\"Peer sent corrupt signature\");\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in DSA signature!\");\r\n\r\n\t\t/* Remember, s and r are unsigned ints. */\r\n\r\n        byte[] tmp = new byte[20];\r\n\r\n        System.arraycopy(rsArray, 0, tmp, 0, 20);\r\n        BigInteger r = new BigInteger(1, tmp);\r\n\r\n        System.arraycopy(rsArray, 20, tmp, 0, 20);\r\n        BigInteger s = new BigInteger(1, tmp);\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(30, \"decoded ssh-dss signature: first bytes r(\" + ((rsArray[0]) & 0xff) + \"), s(\"\r\n                    + ((rsArray[20]) & 0xff) + \")\");\r\n        }\r\n\r\n        return new DSASignature(r, s);\r\n    }\r\n\r\n    public static boolean verifySignature(byte[] message, DSASignature ds, DSAPublicKey dpk) throws IOException {\r\n        /* Inspired by Bouncycastle's DSASigner class */\r\n\r\n        SHA1 md = new SHA1();\r\n        md.update(message);\r\n        byte[] sha_message = new byte[md.getDigestLength()];\r\n        md.digest(sha_message);\r\n\r\n        BigInteger m = new BigInteger(1, sha_message);\r\n\r\n        BigInteger r = ds.getR();\r\n        BigInteger s = ds.getS();\r\n\r\n        BigInteger g = dpk.getG();\r\n        BigInteger p = dpk.getP();\r\n        BigInteger q = dpk.getQ();\r\n        BigInteger y = dpk.getY();\r\n\r\n        BigInteger zero = BigInteger.ZERO;\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(60, \"ssh-dss signature: m: \" + m.toString(16));\r\n            log.log(60, \"ssh-dss signature: r: \" + r.toString(16));\r\n            log.log(60, \"ssh-dss signature: s: \" + s.toString(16));\r\n            log.log(60, \"ssh-dss signature: g: \" + g.toString(16));\r\n            log.log(60, \"ssh-dss signature: p: \" + p.toString(16));\r\n            log.log(60, \"ssh-dss signature: q: \" + q.toString(16));\r\n            log.log(60, \"ssh-dss signature: y: \" + y.toString(16));\r\n        }\r\n\r\n        if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) {\r\n            log.log(20, \"ssh-dss signature: zero.compareTo(r) >= 0 || q.compareTo(r) <= 0\");\r\n            return false;\r\n        }\r\n\r\n        if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) {\r\n            log.log(20, \"ssh-dss signature: zero.compareTo(s) >= 0 || q.compareTo(s) <= 0\");\r\n            return false;\r\n        }\r\n\r\n        BigInteger w = s.modInverse(q);\r\n\r\n        BigInteger u1 = m.multiply(w).mod(q);\r\n        BigInteger u2 = r.multiply(w).mod(q);\r\n\r\n        u1 = g.modPow(u1, p);\r\n        u2 = y.modPow(u2, p);\r\n\r\n        BigInteger v = u1.multiply(u2).mod(p).mod(q);\r\n\r\n        return v.equals(r);\r\n    }\r\n\r\n    public static DSASignature generateSignature(byte[] message, DSAPrivateKey pk, SecureRandom rnd) {\r\n        SHA1 md = new SHA1();\r\n        md.update(message);\r\n        byte[] sha_message = new byte[md.getDigestLength()];\r\n        md.digest(sha_message);\r\n\r\n        BigInteger m = new BigInteger(1, sha_message);\r\n        BigInteger k;\r\n        int qBitLength = pk.getQ().bitLength();\r\n\r\n        do {\r\n            k = new BigInteger(qBitLength, rnd);\r\n        }\r\n        while (k.compareTo(pk.getQ()) >= 0);\r\n\r\n        BigInteger r = pk.getG().modPow(k, pk.getP()).mod(pk.getQ());\r\n\r\n        k = k.modInverse(pk.getQ()).multiply(m.add((pk).getX().multiply(r)));\r\n\r\n        BigInteger s = k.mod(pk.getQ());\r\n\r\n        return new DSASignature(r, s);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/DSASignature.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * DSASignature.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: DSASignature.java,v 1.1 2005/05/26 14:53:30 cplattne Exp $\r\n */\r\npublic class DSASignature {\r\n    private BigInteger r;\r\n    private BigInteger s;\r\n\r\n    public DSASignature(BigInteger r, BigInteger s) {\r\n        this.r = r;\r\n        this.s = s;\r\n    }\r\n\r\n    public BigInteger getR() {\r\n        return r;\r\n    }\r\n\r\n    public BigInteger getS() {\r\n        return s;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/RSAPrivateKey.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * RSAPrivateKey.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RSAPrivateKey.java,v 1.1 2005/08/11 12:47:29 cplattne Exp $\r\n */\r\npublic class RSAPrivateKey {\r\n    private BigInteger d;\r\n    private BigInteger e;\r\n    private BigInteger n;\r\n\r\n    public RSAPrivateKey(BigInteger d, BigInteger e, BigInteger n) {\r\n        this.d = d;\r\n        this.e = e;\r\n        this.n = n;\r\n    }\r\n\r\n    public BigInteger getD() {\r\n        return d;\r\n    }\r\n\r\n    public BigInteger getE() {\r\n        return e;\r\n    }\r\n\r\n    public BigInteger getN() {\r\n        return n;\r\n    }\r\n\r\n    public RSAPublicKey getPublicKey() {\r\n        return new RSAPublicKey(e, n);\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/RSAPublicKey.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * RSAPublicKey.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RSAPublicKey.java,v 1.2 2005/08/11 12:47:29 cplattne Exp $\r\n */\r\npublic class RSAPublicKey {\r\n    BigInteger e;\r\n    BigInteger n;\r\n\r\n    public RSAPublicKey(BigInteger e, BigInteger n) {\r\n        this.e = e;\r\n        this.n = n;\r\n    }\r\n\r\n    public BigInteger getE() {\r\n        return e;\r\n    }\r\n\r\n    public BigInteger getN() {\r\n        return n;\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/RSASHA1Verify.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport ch.ethz.ssh2.crypto.SimpleDERReader;\r\nimport ch.ethz.ssh2.crypto.digest.SHA1;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.TypesReader;\r\nimport ch.ethz.ssh2.packets.TypesWriter;\r\n\r\nimport java.io.IOException;\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * RSASHA1Verify.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RSASHA1Verify.java,v 1.4 2005/12/07 10:25:49 cplattne Exp $\r\n */\r\npublic class RSASHA1Verify {\r\n    private static final Logger log = Logger.getLogger(RSASHA1Verify.class);\r\n\r\n    public static RSAPublicKey decodeSSHRSAPublicKey(byte[] key) throws IOException {\r\n        TypesReader tr = new TypesReader(key);\r\n\r\n        String key_format = tr.readString();\r\n\r\n        if (key_format.equals(\"ssh-rsa\") == false)\r\n            throw new IllegalArgumentException(\"This is not a ssh-rsa public key\");\r\n\r\n        BigInteger e = tr.readMPINT();\r\n        BigInteger n = tr.readMPINT();\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in RSA public key!\");\r\n\r\n        return new RSAPublicKey(e, n);\r\n    }\r\n\r\n    public static byte[] encodeSSHRSAPublicKey(RSAPublicKey pk) throws IOException {\r\n        TypesWriter tw = new TypesWriter();\r\n\r\n        tw.writeString(\"ssh-rsa\");\r\n        tw.writeMPInt(pk.getE());\r\n        tw.writeMPInt(pk.getN());\r\n\r\n        return tw.getBytes();\r\n    }\r\n\r\n    public static RSASignature decodeSSHRSASignature(byte[] sig) throws IOException {\r\n        TypesReader tr = new TypesReader(sig);\r\n\r\n        String sig_format = tr.readString();\r\n\r\n        if (sig_format.equals(\"ssh-rsa\") == false)\r\n            throw new IOException(\"Peer sent wrong signature format\");\r\n\r\n\t\t/* S is NOT an MPINT. \"The value for 'rsa_signature_blob' is encoded as a string\r\n         * containing s (which is an integer, without lengths or padding, unsigned and in\r\n\t\t * network byte order).\" See also below.\r\n\t\t */\r\n\r\n        byte[] s = tr.readByteString();\r\n\r\n        if (s.length == 0)\r\n            throw new IOException(\"Error in RSA signature, S is empty.\");\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(80, \"Decoding ssh-rsa signature string (length: \" + s.length + \")\");\r\n        }\r\n\r\n        if (tr.remain() != 0)\r\n            throw new IOException(\"Padding in RSA signature!\");\r\n\r\n        return new RSASignature(new BigInteger(1, s));\r\n    }\r\n\r\n    public static byte[] encodeSSHRSASignature(RSASignature sig) throws IOException {\r\n        TypesWriter tw = new TypesWriter();\r\n\r\n        tw.writeString(\"ssh-rsa\");\r\n\r\n\t\t/* S is NOT an MPINT. \"The value for 'rsa_signature_blob' is encoded as a string\r\n\t\t * containing s (which is an integer, without lengths or padding, unsigned and in\r\n\t\t * network byte order).\"\r\n\t\t */\r\n\r\n        byte[] s = sig.getS().toByteArray();\r\n\r\n\t\t/* Remove first zero sign byte, if present */\r\n\r\n        if ((s.length > 1) && (s[0] == 0x00))\r\n            tw.writeString(s, 1, s.length - 1);\r\n        else\r\n            tw.writeString(s, 0, s.length);\r\n\r\n        return tw.getBytes();\r\n    }\r\n\r\n    public static RSASignature generateSignature(byte[] message, RSAPrivateKey pk) throws IOException {\r\n        SHA1 md = new SHA1();\r\n        md.update(message);\r\n        byte[] sha_message = new byte[md.getDigestLength()];\r\n        md.digest(sha_message);\r\n\r\n        byte[] der_header = new byte[]{0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00,\r\n                0x04, 0x14};\r\n\r\n        int rsa_block_len = (pk.getN().bitLength() + 7) / 8;\r\n\r\n        int num_pad = rsa_block_len - (2 + der_header.length + sha_message.length) - 1;\r\n\r\n        if (num_pad < 8)\r\n            throw new IOException(\"Cannot sign with RSA, message too long\");\r\n\r\n        byte[] sig = new byte[der_header.length + sha_message.length + 2 + num_pad];\r\n\r\n        sig[0] = 0x01;\r\n\r\n        for (int i = 0; i < num_pad; i++) {\r\n            sig[i + 1] = (byte) 0xff;\r\n        }\r\n\r\n        sig[num_pad + 1] = 0x00;\r\n\r\n        System.arraycopy(der_header, 0, sig, 2 + num_pad, der_header.length);\r\n        System.arraycopy(sha_message, 0, sig, 2 + num_pad + der_header.length, sha_message.length);\r\n\r\n        BigInteger m = new BigInteger(1, sig);\r\n\r\n        BigInteger s = m.modPow(pk.getD(), pk.getN());\r\n\r\n        return new RSASignature(s);\r\n    }\r\n\r\n    public static boolean verifySignature(byte[] message, RSASignature ds, RSAPublicKey dpk) throws IOException {\r\n        SHA1 md = new SHA1();\r\n        md.update(message);\r\n        byte[] sha_message = new byte[md.getDigestLength()];\r\n        md.digest(sha_message);\r\n\r\n        BigInteger n = dpk.getN();\r\n        BigInteger e = dpk.getE();\r\n        BigInteger s = ds.getS();\r\n\r\n        if (n.compareTo(s) <= 0) {\r\n            log.log(20, \"ssh-rsa signature: n.compareTo(s) <= 0\");\r\n            return false;\r\n        }\r\n\r\n        int rsa_block_len = (n.bitLength() + 7) / 8;\r\n\r\n\t\t/* And now the show begins */\r\n\r\n        if (rsa_block_len < 1) {\r\n            log.log(20, \"ssh-rsa signature: rsa_block_len < 1\");\r\n            return false;\r\n        }\r\n\r\n        byte[] v = s.modPow(e, n).toByteArray();\r\n\r\n        int startpos = 0;\r\n\r\n        if ((v.length > 0) && (v[0] == 0x00))\r\n            startpos++;\r\n\r\n        if ((v.length - startpos) != (rsa_block_len - 1)) {\r\n            log.log(20, \"ssh-rsa signature: (v.length - startpos) != (rsa_block_len - 1)\");\r\n            return false;\r\n        }\r\n\r\n        if (v[startpos] != 0x01) {\r\n            log.log(20, \"ssh-rsa signature: v[startpos] != 0x01\");\r\n            return false;\r\n        }\r\n\r\n        int pos = startpos + 1;\r\n\r\n        while (true) {\r\n            if (pos >= v.length) {\r\n                log.log(20, \"ssh-rsa signature: pos >= v.length\");\r\n                return false;\r\n            }\r\n            if (v[pos] == 0x00)\r\n                break;\r\n            if (v[pos] != (byte) 0xff) {\r\n                log.log(20, \"ssh-rsa signature: v[pos] != (byte) 0xff\");\r\n                return false;\r\n            }\r\n            pos++;\r\n        }\r\n\r\n        int num_pad = pos - (startpos + 1);\r\n\r\n        if (num_pad < 8) {\r\n            log.log(20, \"ssh-rsa signature: num_pad < 8\");\r\n            return false;\r\n        }\r\n\r\n        pos++;\r\n\r\n        if (pos >= v.length) {\r\n            log.log(20, \"ssh-rsa signature: pos >= v.length\");\r\n            return false;\r\n        }\r\n\r\n        SimpleDERReader dr = new SimpleDERReader(v, pos, v.length - pos);\r\n\r\n        byte[] seq = dr.readSequenceAsByteArray();\r\n\r\n        if (dr.available() != 0) {\r\n            log.log(20, \"ssh-rsa signature: dr.available() != 0\");\r\n            return false;\r\n        }\r\n\r\n        dr.resetInput(seq);\r\n\r\n\t\t/* Read digestAlgorithm */\r\n\r\n        byte digestAlgorithm[] = dr.readSequenceAsByteArray();\r\n\r\n\t\t/* Inspired by RFC 3347, however, ignoring the comment regarding old BER based implementations */\r\n\r\n        if ((digestAlgorithm.length < 8) || (digestAlgorithm.length > 9)) {\r\n            log.log(20, \"ssh-rsa signature: (digestAlgorithm.length < 8) || (digestAlgorithm.length > 9)\");\r\n            return false;\r\n        }\r\n\r\n        byte[] digestAlgorithm_sha1 = new byte[]{0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00};\r\n\r\n        for (int i = 0; i < digestAlgorithm.length; i++) {\r\n            if (digestAlgorithm[i] != digestAlgorithm_sha1[i]) {\r\n                log.log(20, \"ssh-rsa signature: digestAlgorithm[i] != digestAlgorithm_sha1[i]\");\r\n                return false;\r\n            }\r\n        }\r\n\r\n        byte[] digest = dr.readOctetString();\r\n\r\n        if (dr.available() != 0) {\r\n            log.log(20, \"ssh-rsa signature: dr.available() != 0 (II)\");\r\n            return false;\r\n        }\r\n\r\n        if (digest.length != sha_message.length) {\r\n            log.log(20, \"ssh-rsa signature: digest.length != sha_message.length\");\r\n            return false;\r\n        }\r\n\r\n        for (int i = 0; i < sha_message.length; i++) {\r\n            if (sha_message[i] != digest[i]) {\r\n                log.log(20, \"ssh-rsa signature: sha_message[i] != digest[i]\");\r\n                return false;\r\n            }\r\n        }\r\n\r\n        return true;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/signature/RSASignature.java",
    "content": "package ch.ethz.ssh2.signature;\r\n\r\nimport java.math.BigInteger;\r\n\r\n\r\n/**\r\n * RSASignature.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: RSASignature.java,v 1.1 2005/08/11 12:47:29 cplattne Exp $\r\n */\r\n\r\npublic class RSASignature {\r\n    BigInteger s;\r\n\r\n    public RSASignature(BigInteger s) {\r\n        this.s = s;\r\n    }\r\n\r\n    public BigInteger getS() {\r\n        return s;\r\n    }\r\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/ClientServerHello.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\nimport ch.ethz.ssh2.Connection;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\n\r\n/**\r\n * ClientServerHello.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: ClientServerHello.java,v 1.8 2006/08/02 11:57:12 cplattne Exp $\r\n */\r\npublic class ClientServerHello {\r\n    String server_line;\r\n    String client_line;\r\n\r\n    String server_versioncomment;\r\n\r\n    public ClientServerHello(InputStream bi, OutputStream bo) throws IOException {\r\n        client_line = \"SSH-2.0-\" + Connection.identification;\r\n\r\n        bo.write((client_line + \"\\r\\n\").getBytes());\r\n        bo.flush();\r\n\r\n        byte[] serverVersion = new byte[512];\r\n\r\n        for (int i = 0; i < 50; i++) {\r\n            int len = readLineRN(bi, serverVersion);\r\n\r\n            server_line = new String(serverVersion, 0, len);\r\n\r\n            if (server_line.startsWith(\"SSH-\"))\r\n                break;\r\n        }\r\n\r\n        if (server_line.startsWith(\"SSH-\") == false)\r\n            throw new IOException(\r\n                    \"Malformed server identification string. There was no line starting with 'SSH-' amongst the first 50 lines.\");\r\n\r\n        if (server_line.startsWith(\"SSH-1.99-\"))\r\n            server_versioncomment = server_line.substring(9);\r\n        else if (server_line.startsWith(\"SSH-2.0-\"))\r\n            server_versioncomment = server_line.substring(8);\r\n        else\r\n            throw new IOException(\"Server uses incompatible protocol, it is not SSH-2 compatible.\");\r\n    }\r\n\r\n    public final static int readLineRN(InputStream is, byte[] buffer) throws IOException {\r\n        int pos = 0;\r\n        boolean need10 = false;\r\n        int len = 0;\r\n        while (true) {\r\n            int c = is.read();\r\n            if (c == -1)\r\n                throw new IOException(\"Premature connection close\");\r\n\r\n            buffer[pos++] = (byte) c;\r\n\r\n            if (c == 13) {\r\n                need10 = true;\r\n                continue;\r\n            }\r\n\r\n            if (c == 10)\r\n                break;\r\n\r\n            if (need10 == true)\r\n                throw new IOException(\"Malformed line sent by the server, the line does not end correctly.\");\r\n\r\n            len++;\r\n            if (pos >= buffer.length)\r\n                throw new IOException(\"The server sent a too long line.\");\r\n        }\r\n\r\n        return len;\r\n    }\r\n\r\n    /**\r\n     * @return Returns the client_versioncomment.\r\n     */\r\n    public byte[] getClientString() {\r\n        return client_line.getBytes();\r\n    }\r\n\r\n    /**\r\n     * @return Returns the server_versioncomment.\r\n     */\r\n    public byte[] getServerString() {\r\n        return server_line.getBytes();\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/KexManager.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\nimport ch.ethz.ssh2.ConnectionInfo;\r\nimport ch.ethz.ssh2.DHGexParameters;\r\nimport ch.ethz.ssh2.ServerHostKeyVerifier;\r\nimport ch.ethz.ssh2.crypto.CryptoWishList;\r\nimport ch.ethz.ssh2.crypto.KeyMaterial;\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipher;\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipherFactory;\r\nimport ch.ethz.ssh2.crypto.dh.DhExchange;\r\nimport ch.ethz.ssh2.crypto.dh.DhGroupExchange;\r\nimport ch.ethz.ssh2.crypto.digest.MAC;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.*;\r\nimport ch.ethz.ssh2.signature.*;\r\n\r\nimport java.io.IOException;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * KexManager.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: KexManager.java,v 1.11 2006/09/20 12:51:37 cplattne Exp $\r\n */\r\npublic class KexManager {\r\n    private static final Logger log = Logger.getLogger(KexManager.class);\r\n    final Object accessLock = new Object();\r\n    final TransportManager tm;\r\n    final String hostname;\r\n    final int port;\r\n    final SecureRandom rnd;\r\n    KexState kxs;\r\n    int kexCount = 0;\r\n    KeyMaterial km;\r\n    byte[] sessionId;\r\n    ClientServerHello csh;\r\n    ConnectionInfo lastConnInfo = null;\r\n    boolean connectionClosed = false;\r\n    boolean ignore_next_kex_packet = false;\r\n    CryptoWishList nextKEXcryptoWishList;\r\n    DHGexParameters nextKEXdhgexParameters;\r\n    ServerHostKeyVerifier verifier;\r\n\r\n    public KexManager(TransportManager tm, ClientServerHello csh, CryptoWishList initialCwl, String hostname, int port,\r\n                      ServerHostKeyVerifier keyVerifier, SecureRandom rnd) {\r\n        this.tm = tm;\r\n        this.csh = csh;\r\n        this.nextKEXcryptoWishList = initialCwl;\r\n        this.nextKEXdhgexParameters = new DHGexParameters();\r\n        this.hostname = hostname;\r\n        this.port = port;\r\n        this.verifier = keyVerifier;\r\n        this.rnd = rnd;\r\n    }\r\n\r\n    public static final String[] getDefaultServerHostkeyAlgorithmList() {\r\n        return new String[]{\"ssh-rsa\", \"ssh-dss\"};\r\n    }\r\n\r\n    public static final void checkServerHostkeyAlgorithmsList(String[] algos) {\r\n        for (int i = 0; i < algos.length; i++) {\r\n            if ((\"ssh-rsa\".equals(algos[i]) == false) && (\"ssh-dss\".equals(algos[i]) == false))\r\n                throw new IllegalArgumentException(\"Unknown server host key algorithm '\" + algos[i] + \"'\");\r\n        }\r\n    }\r\n\r\n    public static final String[] getDefaultKexAlgorithmList() {\r\n        return new String[]{\"diffie-hellman-group-exchange-sha1\", \"diffie-hellman-group14-sha1\",\r\n                \"diffie-hellman-group1-sha1\"};\r\n    }\r\n\r\n    public static final void checkKexAlgorithmList(String[] algos) {\r\n        for (int i = 0; i < algos.length; i++) {\r\n            if (\"diffie-hellman-group-exchange-sha1\".equals(algos[i]))\r\n                continue;\r\n\r\n            if (\"diffie-hellman-group14-sha1\".equals(algos[i]))\r\n                continue;\r\n\r\n            if (\"diffie-hellman-group1-sha1\".equals(algos[i]))\r\n                continue;\r\n\r\n            throw new IllegalArgumentException(\"Unknown kex algorithm '\" + algos[i] + \"'\");\r\n        }\r\n    }\r\n\r\n    public ConnectionInfo getOrWaitForConnectionInfo(int minKexCount) throws IOException {\r\n        synchronized (accessLock) {\r\n            while (true) {\r\n                if ((lastConnInfo != null) && (lastConnInfo.keyExchangeCounter >= minKexCount))\r\n                    return lastConnInfo;\r\n\r\n                if (connectionClosed)\r\n                    throw (IOException) new IOException(\"Key exchange was not finished, connection is closed.\")\r\n                            .initCause(tm.getReasonClosedCause());\r\n\r\n                try {\r\n                    accessLock.wait();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    private String getFirstMatch(String[] client, String[] server) throws NegotiateException {\r\n        if (client == null || server == null)\r\n            throw new IllegalArgumentException();\r\n\r\n        if (client.length == 0)\r\n            return null;\r\n\r\n        for (int i = 0; i < client.length; i++) {\r\n            for (int j = 0; j < server.length; j++) {\r\n                if (client[i].equals(server[j]))\r\n                    return client[i];\r\n            }\r\n        }\r\n        throw new NegotiateException();\r\n    }\r\n\r\n    private boolean compareFirstOfNameList(String[] a, String[] b) {\r\n        if (a == null || b == null)\r\n            throw new IllegalArgumentException();\r\n\r\n        if ((a.length == 0) && (b.length == 0))\r\n            return true;\r\n\r\n        if ((a.length == 0) || (b.length == 0))\r\n            return false;\r\n\r\n        return (a[0].equals(b[0]));\r\n    }\r\n\r\n    private boolean isGuessOK(KexParameters cpar, KexParameters spar) {\r\n        if (cpar == null || spar == null)\r\n            throw new IllegalArgumentException();\r\n\r\n        if (compareFirstOfNameList(cpar.kex_algorithms, spar.kex_algorithms) == false) {\r\n            return false;\r\n        }\r\n\r\n        if (compareFirstOfNameList(cpar.server_host_key_algorithms, spar.server_host_key_algorithms) == false) {\r\n            return false;\r\n        }\r\n\r\n\t\t/*\r\n         * We do NOT check here if the other algorithms can be agreed on, this\r\n\t\t * is just a check if kex_algorithms and server_host_key_algorithms were\r\n\t\t * guessed right!\r\n\t\t */\r\n\r\n        return true;\r\n    }\r\n\r\n    private NegotiatedParameters mergeKexParameters(KexParameters client, KexParameters server) {\r\n        NegotiatedParameters np = new NegotiatedParameters();\r\n\r\n        try {\r\n            np.kex_algo = getFirstMatch(client.kex_algorithms, server.kex_algorithms);\r\n\r\n            log.log(20, \"kex_algo=\" + np.kex_algo);\r\n\r\n            np.server_host_key_algo = getFirstMatch(client.server_host_key_algorithms,\r\n                    server.server_host_key_algorithms);\r\n\r\n            log.log(20, \"server_host_key_algo=\" + np.server_host_key_algo);\r\n\r\n            np.enc_algo_client_to_server = getFirstMatch(client.encryption_algorithms_client_to_server,\r\n                    server.encryption_algorithms_client_to_server);\r\n            np.enc_algo_server_to_client = getFirstMatch(client.encryption_algorithms_server_to_client,\r\n                    server.encryption_algorithms_server_to_client);\r\n\r\n            log.log(20, \"enc_algo_client_to_server=\" + np.enc_algo_client_to_server);\r\n            log.log(20, \"enc_algo_server_to_client=\" + np.enc_algo_server_to_client);\r\n\r\n            np.mac_algo_client_to_server = getFirstMatch(client.mac_algorithms_client_to_server,\r\n                    server.mac_algorithms_client_to_server);\r\n            np.mac_algo_server_to_client = getFirstMatch(client.mac_algorithms_server_to_client,\r\n                    server.mac_algorithms_server_to_client);\r\n\r\n            log.log(20, \"mac_algo_client_to_server=\" + np.mac_algo_client_to_server);\r\n            log.log(20, \"mac_algo_server_to_client=\" + np.mac_algo_server_to_client);\r\n\r\n            np.comp_algo_client_to_server = getFirstMatch(client.compression_algorithms_client_to_server,\r\n                    server.compression_algorithms_client_to_server);\r\n            np.comp_algo_server_to_client = getFirstMatch(client.compression_algorithms_server_to_client,\r\n                    server.compression_algorithms_server_to_client);\r\n\r\n            log.log(20, \"comp_algo_client_to_server=\" + np.comp_algo_client_to_server);\r\n            log.log(20, \"comp_algo_server_to_client=\" + np.comp_algo_server_to_client);\r\n\r\n        } catch (NegotiateException e) {\r\n            return null;\r\n        }\r\n\r\n        try {\r\n            np.lang_client_to_server = getFirstMatch(client.languages_client_to_server,\r\n                    server.languages_client_to_server);\r\n        } catch (NegotiateException e1) {\r\n            np.lang_client_to_server = null;\r\n        }\r\n\r\n        try {\r\n            np.lang_server_to_client = getFirstMatch(client.languages_server_to_client,\r\n                    server.languages_server_to_client);\r\n        } catch (NegotiateException e2) {\r\n            np.lang_server_to_client = null;\r\n        }\r\n\r\n        if (isGuessOK(client, server))\r\n            np.guessOK = true;\r\n\r\n        return np;\r\n    }\r\n\r\n    public synchronized void initiateKEX(CryptoWishList cwl, DHGexParameters dhgex) throws IOException {\r\n        nextKEXcryptoWishList = cwl;\r\n        nextKEXdhgexParameters = dhgex;\r\n\r\n        if (kxs == null) {\r\n            kxs = new KexState();\r\n\r\n            kxs.dhgexParameters = nextKEXdhgexParameters;\r\n            PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList, rnd);\r\n            kxs.localKEX = kp;\r\n            tm.sendKexMessage(kp.getPayload());\r\n        }\r\n    }\r\n\r\n    private boolean establishKeyMaterial() {\r\n        try {\r\n            int mac_cs_key_len = MAC.getKeyLen(kxs.np.mac_algo_client_to_server);\r\n            int enc_cs_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_client_to_server);\r\n            int enc_cs_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_client_to_server);\r\n\r\n            int mac_sc_key_len = MAC.getKeyLen(kxs.np.mac_algo_server_to_client);\r\n            int enc_sc_key_len = BlockCipherFactory.getKeySize(kxs.np.enc_algo_server_to_client);\r\n            int enc_sc_block_len = BlockCipherFactory.getBlockSize(kxs.np.enc_algo_server_to_client);\r\n\r\n            km = KeyMaterial.create(\"SHA1\", kxs.H, kxs.K, sessionId, enc_cs_key_len, enc_cs_block_len, mac_cs_key_len,\r\n                    enc_sc_key_len, enc_sc_block_len, mac_sc_key_len);\r\n        } catch (IllegalArgumentException e) {\r\n            return false;\r\n        }\r\n        return true;\r\n    }\r\n\r\n    private void finishKex() throws IOException {\r\n        if (sessionId == null)\r\n            sessionId = kxs.H;\r\n\r\n        establishKeyMaterial();\r\n\r\n\t\t/* Tell the other side that we start using the new material */\r\n\r\n        PacketNewKeys ign = new PacketNewKeys();\r\n        tm.sendKexMessage(ign.getPayload());\r\n\r\n        BlockCipher cbc;\r\n        MAC mac;\r\n\r\n        try {\r\n            cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_client_to_server, true, km.enc_key_client_to_server,\r\n                    km.initial_iv_client_to_server);\r\n\r\n            mac = new MAC(kxs.np.mac_algo_client_to_server, km.integrity_key_client_to_server);\r\n\r\n        } catch (IllegalArgumentException e1) {\r\n            throw new IOException(\"Fatal error during MAC startup!\");\r\n        }\r\n\r\n        tm.changeSendCipher(cbc, mac);\r\n        tm.kexFinished();\r\n    }\r\n\r\n    private boolean verifySignature(byte[] sig, byte[] hostkey) throws IOException {\r\n        if (kxs.np.server_host_key_algo.equals(\"ssh-rsa\")) {\r\n            RSASignature rs = RSASHA1Verify.decodeSSHRSASignature(sig);\r\n            RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(hostkey);\r\n\r\n            log.log(50, \"Verifying ssh-rsa signature\");\r\n\r\n            return RSASHA1Verify.verifySignature(kxs.H, rs, rpk);\r\n        }\r\n\r\n        if (kxs.np.server_host_key_algo.equals(\"ssh-dss\")) {\r\n            DSASignature ds = DSASHA1Verify.decodeSSHDSASignature(sig);\r\n            DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(hostkey);\r\n\r\n            log.log(50, \"Verifying ssh-dss signature\");\r\n\r\n            return DSASHA1Verify.verifySignature(kxs.H, ds, dpk);\r\n        }\r\n\r\n        throw new IOException(\"Unknown server host key algorithm '\" + kxs.np.server_host_key_algo + \"'\");\r\n    }\r\n\r\n    public synchronized void handleMessage(byte[] msg, int msglen) throws IOException {\r\n        PacketKexInit kip;\r\n\r\n        if (msg == null) {\r\n            synchronized (accessLock) {\r\n                connectionClosed = true;\r\n                accessLock.notifyAll();\r\n                return;\r\n            }\r\n        }\r\n\r\n        if ((kxs == null) && (msg[0] != Packets.SSH_MSG_KEXINIT))\r\n            throw new IOException(\"Unexpected KEX message (type \" + msg[0] + \")\");\r\n\r\n        if (ignore_next_kex_packet) {\r\n            ignore_next_kex_packet = false;\r\n            return;\r\n        }\r\n\r\n        if (msg[0] == Packets.SSH_MSG_KEXINIT) {\r\n            if ((kxs != null) && (kxs.state != 0))\r\n                throw new IOException(\"Unexpected SSH_MSG_KEXINIT message during on-going kex exchange!\");\r\n\r\n            if (kxs == null) {\r\n\t\t\t\t/*\r\n\t\t\t\t * Ah, OK, peer wants to do KEX. Let's be nice and play\r\n\t\t\t\t * together.\r\n\t\t\t\t */\r\n                kxs = new KexState();\r\n                kxs.dhgexParameters = nextKEXdhgexParameters;\r\n                kip = new PacketKexInit(nextKEXcryptoWishList, rnd);\r\n                kxs.localKEX = kip;\r\n                tm.sendKexMessage(kip.getPayload());\r\n            }\r\n\r\n            kip = new PacketKexInit(msg, 0, msglen);\r\n            kxs.remoteKEX = kip;\r\n\r\n            kxs.np = mergeKexParameters(kxs.localKEX.getKexParameters(), kxs.remoteKEX.getKexParameters());\r\n\r\n            if (kxs.np == null)\r\n                throw new IOException(\"Cannot negotiate, proposals do not match.\");\r\n\r\n            if (kxs.remoteKEX.isFirst_kex_packet_follows() && (kxs.np.guessOK == false)) {\r\n\t\t\t\t/*\r\n\t\t\t\t * Guess was wrong, we need to ignore the next kex packet.\r\n\t\t\t\t */\r\n\r\n                ignore_next_kex_packet = true;\r\n            }\r\n\r\n            if (kxs.np.kex_algo.equals(\"diffie-hellman-group-exchange-sha1\")) {\r\n                if (kxs.dhgexParameters.getMin_group_len() == 0) {\r\n                    PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters);\r\n                    tm.sendKexMessage(dhgexreq.getPayload());\r\n\r\n                } else {\r\n                    PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters);\r\n                    tm.sendKexMessage(dhgexreq.getPayload());\r\n                }\r\n                kxs.state = 1;\r\n                return;\r\n            }\r\n\r\n            if (kxs.np.kex_algo.equals(\"diffie-hellman-group1-sha1\")\r\n                    || kxs.np.kex_algo.equals(\"diffie-hellman-group14-sha1\")) {\r\n                kxs.dhx = new DhExchange();\r\n\r\n                if (kxs.np.kex_algo.equals(\"diffie-hellman-group1-sha1\"))\r\n                    kxs.dhx.init(1, rnd);\r\n                else\r\n                    kxs.dhx.init(14, rnd);\r\n\r\n                PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE());\r\n                tm.sendKexMessage(kp.getPayload());\r\n                kxs.state = 1;\r\n                return;\r\n            }\r\n\r\n            throw new IllegalStateException(\"Unkown KEX method!\");\r\n        }\r\n\r\n        if (msg[0] == Packets.SSH_MSG_NEWKEYS) {\r\n            if (km == null)\r\n                throw new IOException(\"Peer sent SSH_MSG_NEWKEYS, but I have no key material ready!\");\r\n\r\n            BlockCipher cbc;\r\n            MAC mac;\r\n\r\n            try {\r\n                cbc = BlockCipherFactory.createCipher(kxs.np.enc_algo_server_to_client, false,\r\n                        km.enc_key_server_to_client, km.initial_iv_server_to_client);\r\n\r\n                mac = new MAC(kxs.np.mac_algo_server_to_client, km.integrity_key_server_to_client);\r\n\r\n            } catch (IllegalArgumentException e1) {\r\n                throw new IOException(\"Fatal error during MAC startup!\");\r\n            }\r\n\r\n            tm.changeRecvCipher(cbc, mac);\r\n\r\n            ConnectionInfo sci = new ConnectionInfo();\r\n\r\n            kexCount++;\r\n\r\n            sci.keyExchangeAlgorithm = kxs.np.kex_algo;\r\n            sci.keyExchangeCounter = kexCount;\r\n            sci.clientToServerCryptoAlgorithm = kxs.np.enc_algo_client_to_server;\r\n            sci.serverToClientCryptoAlgorithm = kxs.np.enc_algo_server_to_client;\r\n            sci.clientToServerMACAlgorithm = kxs.np.mac_algo_client_to_server;\r\n            sci.serverToClientMACAlgorithm = kxs.np.mac_algo_server_to_client;\r\n            sci.serverHostKeyAlgorithm = kxs.np.server_host_key_algo;\r\n            sci.serverHostKey = kxs.hostkey;\r\n\r\n            synchronized (accessLock) {\r\n                lastConnInfo = sci;\r\n                accessLock.notifyAll();\r\n            }\r\n\r\n            kxs = null;\r\n            return;\r\n        }\r\n\r\n        if ((kxs == null) || (kxs.state == 0))\r\n            throw new IOException(\"Unexpected Kex submessage!\");\r\n\r\n        if (kxs.np.kex_algo.equals(\"diffie-hellman-group-exchange-sha1\")) {\r\n            if (kxs.state == 1) {\r\n                PacketKexDhGexGroup dhgexgrp = new PacketKexDhGexGroup(msg, 0, msglen);\r\n                kxs.dhgx = new DhGroupExchange(dhgexgrp.getP(), dhgexgrp.getG());\r\n                kxs.dhgx.init(rnd);\r\n                PacketKexDhGexInit dhgexinit = new PacketKexDhGexInit(kxs.dhgx.getE());\r\n                tm.sendKexMessage(dhgexinit.getPayload());\r\n                kxs.state = 2;\r\n                return;\r\n            }\r\n\r\n            if (kxs.state == 2) {\r\n                PacketKexDhGexReply dhgexrpl = new PacketKexDhGexReply(msg, 0, msglen);\r\n\r\n                kxs.hostkey = dhgexrpl.getHostKey();\r\n\r\n                if (verifier != null) {\r\n                    boolean vres = false;\r\n\r\n                    try {\r\n                        vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey);\r\n                    } catch (Exception e) {\r\n                        throw (IOException) new IOException(\r\n                                \"The server hostkey was not accepted by the verifier callback.\").initCause(e);\r\n                    }\r\n\r\n                    if (vres == false)\r\n                        throw new IOException(\"The server hostkey was not accepted by the verifier callback\");\r\n                }\r\n\r\n                kxs.dhgx.setF(dhgexrpl.getF());\r\n\r\n                try {\r\n                    kxs.H = kxs.dhgx.calculateH(csh.getClientString(), csh.getServerString(),\r\n                            kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), dhgexrpl.getHostKey(),\r\n                            kxs.dhgexParameters);\r\n                } catch (IllegalArgumentException e) {\r\n                    throw (IOException) new IOException(\"KEX error.\").initCause(e);\r\n                }\r\n\r\n                boolean res = verifySignature(dhgexrpl.getSignature(), kxs.hostkey);\r\n\r\n                if (res == false)\r\n                    throw new IOException(\"Hostkey signature sent by remote is wrong!\");\r\n\r\n                kxs.K = kxs.dhgx.getK();\r\n\r\n                finishKex();\r\n                kxs.state = -1;\r\n                return;\r\n            }\r\n\r\n            throw new IllegalStateException(\"Illegal State in KEX Exchange!\");\r\n        }\r\n\r\n        if (kxs.np.kex_algo.equals(\"diffie-hellman-group1-sha1\")\r\n                || kxs.np.kex_algo.equals(\"diffie-hellman-group14-sha1\")) {\r\n            if (kxs.state == 1) {\r\n\r\n                PacketKexDHReply dhr = new PacketKexDHReply(msg, 0, msglen);\r\n\r\n                kxs.hostkey = dhr.getHostKey();\r\n\r\n                if (verifier != null) {\r\n                    boolean vres = false;\r\n\r\n                    try {\r\n                        vres = verifier.verifyServerHostKey(hostname, port, kxs.np.server_host_key_algo, kxs.hostkey);\r\n                    } catch (Exception e) {\r\n                        throw (IOException) new IOException(\r\n                                \"The server hostkey was not accepted by the verifier callback.\").initCause(e);\r\n                    }\r\n\r\n                    if (vres == false)\r\n                        throw new IOException(\"The server hostkey was not accepted by the verifier callback\");\r\n                }\r\n\r\n                kxs.dhx.setF(dhr.getF());\r\n\r\n                try {\r\n                    kxs.H = kxs.dhx.calculateH(csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(),\r\n                            kxs.remoteKEX.getPayload(), dhr.getHostKey());\r\n                } catch (IllegalArgumentException e) {\r\n                    throw (IOException) new IOException(\"KEX error.\").initCause(e);\r\n                }\r\n\r\n                boolean res = verifySignature(dhr.getSignature(), kxs.hostkey);\r\n\r\n                if (res == false)\r\n                    throw new IOException(\"Hostkey signature sent by remote is wrong!\");\r\n\r\n                kxs.K = kxs.dhx.getK();\r\n\r\n                finishKex();\r\n                kxs.state = -1;\r\n                return;\r\n            }\r\n        }\r\n\r\n        throw new IllegalStateException(\"Unkown KEX method! (\" + kxs.np.kex_algo + \")\");\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/KexParameters.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\n/**\r\n * KexParameters.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: KexParameters.java,v 1.1 2005/05/26 14:53:28 cplattne Exp $\r\n */\r\npublic class KexParameters {\r\n    public byte[] cookie;\r\n    public String[] kex_algorithms;\r\n    public String[] server_host_key_algorithms;\r\n    public String[] encryption_algorithms_client_to_server;\r\n    public String[] encryption_algorithms_server_to_client;\r\n    public String[] mac_algorithms_client_to_server;\r\n    public String[] mac_algorithms_server_to_client;\r\n    public String[] compression_algorithms_client_to_server;\r\n    public String[] compression_algorithms_server_to_client;\r\n    public String[] languages_client_to_server;\r\n    public String[] languages_server_to_client;\r\n    public boolean first_kex_packet_follows;\r\n    public int reserved_field1;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/KexState.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\n\r\nimport ch.ethz.ssh2.DHGexParameters;\r\nimport ch.ethz.ssh2.crypto.dh.DhExchange;\r\nimport ch.ethz.ssh2.crypto.dh.DhGroupExchange;\r\nimport ch.ethz.ssh2.packets.PacketKexInit;\r\n\r\nimport java.math.BigInteger;\r\n\r\n/**\r\n * KexState.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: KexState.java,v 1.3 2005/06/06 12:44:23 cplattne Exp $\r\n */\r\npublic class KexState {\r\n    public PacketKexInit localKEX;\r\n    public PacketKexInit remoteKEX;\r\n    public NegotiatedParameters np;\r\n    public int state = 0;\r\n\r\n    public BigInteger K;\r\n    public byte[] H;\r\n\r\n    public byte[] hostkey;\r\n\r\n    public DhExchange dhx;\r\n    public DhGroupExchange dhgx;\r\n    public DHGexParameters dhgexParameters;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/MessageHandler.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\nimport java.io.IOException;\r\n\r\n/**\r\n * MessageHandler.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: MessageHandler.java,v 1.1 2005/05/26 14:53:29 cplattne Exp $\r\n */\r\npublic interface MessageHandler {\r\n    public void handleMessage(byte[] msg, int msglen) throws IOException;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/NegotiateException.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\n/**\r\n * NegotiateException.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: NegotiateException.java,v 1.1 2005/05/26 14:53:29 cplattne Exp $\r\n */\r\npublic class NegotiateException extends Exception {\r\n    private static final long serialVersionUID = 3689910669428143157L;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/NegotiatedParameters.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\n/**\r\n * NegotiatedParameters.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: NegotiatedParameters.java,v 1.1 2005/05/26 14:53:28 cplattne Exp $\r\n */\r\npublic class NegotiatedParameters {\r\n    public boolean guessOK;\r\n    public String kex_algo;\r\n    public String server_host_key_algo;\r\n    public String enc_algo_client_to_server;\r\n    public String enc_algo_server_to_client;\r\n    public String mac_algo_client_to_server;\r\n    public String mac_algo_server_to_client;\r\n    public String comp_algo_client_to_server;\r\n    public String comp_algo_server_to_client;\r\n    public String lang_client_to_server;\r\n    public String lang_server_to_client;\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/TransportConnection.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipher;\r\nimport ch.ethz.ssh2.crypto.cipher.CipherInputStream;\r\nimport ch.ethz.ssh2.crypto.cipher.CipherOutputStream;\r\nimport ch.ethz.ssh2.crypto.cipher.NullCipher;\r\nimport ch.ethz.ssh2.crypto.digest.MAC;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.Packets;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.security.SecureRandom;\r\n\r\n/**\r\n * TransportConnection.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: TransportConnection.java,v 1.8 2006/02/14 19:43:15 cplattne Exp $\r\n */\r\npublic class TransportConnection {\r\n    private static final Logger log = Logger.getLogger(TransportConnection.class);\r\n    final byte[] send_padding_buffer = new byte[256];\r\n    final byte[] send_packet_header_buffer = new byte[5];\r\n    final byte[] recv_padding_buffer = new byte[256];\r\n    final byte[] recv_packet_header_buffer = new byte[5];\r\n    final SecureRandom rnd;\r\n\r\n\t/* Depends on current MAC and CIPHER */\r\n    int send_seq_number = 0;\r\n    int recv_seq_number = 0;\r\n    CipherInputStream cis;\r\n    CipherOutputStream cos;\r\n    boolean useRandomPadding = false;\r\n    MAC send_mac;\r\n    byte[] send_mac_buffer;\r\n\r\n\t/* won't change */\r\n    int send_padd_blocksize = 8;\r\n    MAC recv_mac;\r\n    byte[] recv_mac_buffer;\r\n    byte[] recv_mac_buffer_cmp;\r\n    int recv_padd_blocksize = 8;\r\n    boolean recv_packet_header_present = false;\r\n    ClientServerHello csh;\r\n\r\n    public TransportConnection(InputStream is, OutputStream os, SecureRandom rnd) {\r\n        this.cis = new CipherInputStream(new NullCipher(), is);\r\n        this.cos = new CipherOutputStream(new NullCipher(), os);\r\n        this.rnd = rnd;\r\n    }\r\n\r\n    public void changeRecvCipher(BlockCipher bc, MAC mac) {\r\n        cis.changeCipher(bc);\r\n        recv_mac = mac;\r\n        recv_mac_buffer = (mac != null) ? new byte[mac.size()] : null;\r\n        recv_mac_buffer_cmp = (mac != null) ? new byte[mac.size()] : null;\r\n        recv_padd_blocksize = bc.getBlockSize();\r\n        if (recv_padd_blocksize < 8)\r\n            recv_padd_blocksize = 8;\r\n    }\r\n\r\n    public void changeSendCipher(BlockCipher bc, MAC mac) {\r\n        if ((bc instanceof NullCipher) == false) {\r\n            /* Only use zero byte padding for the first few packets */\r\n            useRandomPadding = true;\r\n\t\t\t/* Once we start encrypting, there is no way back */\r\n        }\r\n\r\n        cos.changeCipher(bc);\r\n        send_mac = mac;\r\n        send_mac_buffer = (mac != null) ? new byte[mac.size()] : null;\r\n        send_padd_blocksize = bc.getBlockSize();\r\n        if (send_padd_blocksize < 8)\r\n            send_padd_blocksize = 8;\r\n    }\r\n\r\n    public void sendMessage(byte[] message) throws IOException {\r\n        sendMessage(message, 0, message.length, 0);\r\n    }\r\n\r\n    public void sendMessage(byte[] message, int off, int len) throws IOException {\r\n        sendMessage(message, off, len, 0);\r\n    }\r\n\r\n    public int getPacketOverheadEstimate() {\r\n        // return an estimate for the paket overhead (for send operations)\r\n        return 5 + 4 + (send_padd_blocksize - 1) + send_mac_buffer.length;\r\n    }\r\n\r\n    public void sendMessage(byte[] message, int off, int len, int padd) throws IOException {\r\n        if (padd < 4)\r\n            padd = 4;\r\n        else if (padd > 64)\r\n            padd = 64;\r\n\r\n        int packet_len = 5 + len + padd; /* Minimum allowed padding is 4 */\r\n\r\n        int slack = packet_len % send_padd_blocksize;\r\n\r\n        if (slack != 0) {\r\n            packet_len += (send_padd_blocksize - slack);\r\n        }\r\n\r\n        if (packet_len < 16)\r\n            packet_len = 16;\r\n\r\n        int padd_len = packet_len - (5 + len);\r\n\r\n        if (useRandomPadding) {\r\n            for (int i = 0; i < padd_len; i = i + 4) {\r\n\t\t\t\t/*\r\n\t\t\t\t * don't waste calls to rnd.nextInt() (by using only 8bit of the\r\n\t\t\t\t * output). just believe me: even though we may write here up to 3\r\n\t\t\t\t * bytes which won't be used, there is no \"buffer overflow\" (i.e.,\r\n\t\t\t\t * arrayindexoutofbounds). the padding buffer is big enough =) (256\r\n\t\t\t\t * bytes, and that is bigger than any current cipher block size + 64).\r\n\t\t\t\t */\r\n\r\n                int r = rnd.nextInt();\r\n                send_padding_buffer[i] = (byte) r;\r\n                send_padding_buffer[i + 1] = (byte) (r >> 8);\r\n                send_padding_buffer[i + 2] = (byte) (r >> 16);\r\n                send_padding_buffer[i + 3] = (byte) (r >> 24);\r\n            }\r\n        } else {\r\n\t\t\t/* use zero padding for unencrypted traffic */\r\n            for (int i = 0; i < padd_len; i++)\r\n                send_padding_buffer[i] = 0;\r\n\t\t\t/* Actually this code is paranoid: we never filled any\r\n\t\t\t * bytes into the padding buffer so far, therefore it should\r\n\t\t\t * consist of zeros only.\r\n\t\t\t */\r\n        }\r\n\r\n        send_packet_header_buffer[0] = (byte) ((packet_len - 4) >> 24);\r\n        send_packet_header_buffer[1] = (byte) ((packet_len - 4) >> 16);\r\n        send_packet_header_buffer[2] = (byte) ((packet_len - 4) >> 8);\r\n        send_packet_header_buffer[3] = (byte) ((packet_len - 4));\r\n        send_packet_header_buffer[4] = (byte) padd_len;\r\n\r\n        cos.write(send_packet_header_buffer, 0, 5);\r\n        cos.write(message, off, len);\r\n        cos.write(send_padding_buffer, 0, padd_len);\r\n\r\n        if (send_mac != null) {\r\n            send_mac.initMac(send_seq_number);\r\n            send_mac.update(send_packet_header_buffer, 0, 5);\r\n            send_mac.update(message, off, len);\r\n            send_mac.update(send_padding_buffer, 0, padd_len);\r\n\r\n            send_mac.getMac(send_mac_buffer, 0);\r\n            cos.writePlain(send_mac_buffer, 0, send_mac_buffer.length);\r\n        }\r\n\r\n        cos.flush();\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(90, \"Sent \" + Packets.getMessageName(message[off] & 0xff) + \" \" + len + \" bytes payload\");\r\n        }\r\n\r\n        send_seq_number++;\r\n    }\r\n\r\n    public int peekNextMessageLength() throws IOException {\r\n        if (recv_packet_header_present == false) {\r\n            cis.read(recv_packet_header_buffer, 0, 5);\r\n            recv_packet_header_present = true;\r\n        }\r\n\r\n        int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)\r\n                | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)\r\n                | ((recv_packet_header_buffer[3] & 0xff));\r\n\r\n        int padding_length = recv_packet_header_buffer[4] & 0xff;\r\n\r\n        if (packet_length > 35000 || packet_length < 12)\r\n            throw new IOException(\"Illegal packet size! (\" + packet_length + \")\");\r\n\r\n        int payload_length = packet_length - padding_length - 1;\r\n\r\n        if (payload_length < 0)\r\n            throw new IOException(\"Illegal padding_length in packet from remote (\" + padding_length + \")\");\r\n\r\n        return payload_length;\r\n    }\r\n\r\n    public int receiveMessage(byte buffer[], int off, int len) throws IOException {\r\n        if (recv_packet_header_present == false) {\r\n            cis.read(recv_packet_header_buffer, 0, 5);\r\n        } else\r\n            recv_packet_header_present = false;\r\n\r\n        int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)\r\n                | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)\r\n                | ((recv_packet_header_buffer[3] & 0xff));\r\n\r\n        int padding_length = recv_packet_header_buffer[4] & 0xff;\r\n\r\n        if (packet_length > 35000 || packet_length < 12)\r\n            throw new IOException(\"Illegal packet size! (\" + packet_length + \")\");\r\n\r\n        int payload_length = packet_length - padding_length - 1;\r\n\r\n        if (payload_length < 0)\r\n            throw new IOException(\"Illegal padding_length in packet from remote (\" + padding_length + \")\");\r\n\r\n        if (payload_length >= len)\r\n            throw new IOException(\"Receive buffer too small (\" + len + \", need \" + payload_length + \")\");\r\n\r\n        cis.read(buffer, off, payload_length);\r\n        cis.read(recv_padding_buffer, 0, padding_length);\r\n\r\n        if (recv_mac != null) {\r\n            cis.readPlain(recv_mac_buffer, 0, recv_mac_buffer.length);\r\n\r\n            recv_mac.initMac(recv_seq_number);\r\n            recv_mac.update(recv_packet_header_buffer, 0, 5);\r\n            recv_mac.update(buffer, off, payload_length);\r\n            recv_mac.update(recv_padding_buffer, 0, padding_length);\r\n            recv_mac.getMac(recv_mac_buffer_cmp, 0);\r\n\r\n            for (int i = 0; i < recv_mac_buffer.length; i++) {\r\n                if (recv_mac_buffer[i] != recv_mac_buffer_cmp[i])\r\n                    throw new IOException(\"Remote sent corrupt MAC.\");\r\n            }\r\n        }\r\n\r\n        recv_seq_number++;\r\n\r\n        if (log.isEnabled()) {\r\n            log.log(90, \"Received \" + Packets.getMessageName(buffer[off] & 0xff) + \" \" + payload_length\r\n                    + \" bytes payload\");\r\n        }\r\n\r\n        return payload_length;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/transport/TransportManager.java",
    "content": "package ch.ethz.ssh2.transport;\r\n\r\nimport ch.ethz.ssh2.*;\r\nimport ch.ethz.ssh2.crypto.Base64;\r\nimport ch.ethz.ssh2.crypto.CryptoWishList;\r\nimport ch.ethz.ssh2.crypto.cipher.BlockCipher;\r\nimport ch.ethz.ssh2.crypto.digest.MAC;\r\nimport ch.ethz.ssh2.log.Logger;\r\nimport ch.ethz.ssh2.packets.PacketDisconnect;\r\nimport ch.ethz.ssh2.packets.Packets;\r\nimport ch.ethz.ssh2.packets.TypesReader;\r\nimport ch.ethz.ssh2.util.Tokenizer;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.OutputStream;\r\nimport java.net.InetAddress;\r\nimport java.net.InetSocketAddress;\r\nimport java.net.Socket;\r\nimport java.net.UnknownHostException;\r\nimport java.security.SecureRandom;\r\nimport java.util.Vector;\r\n\r\n/*\r\n * Yes, the \"standard\" is a big mess. On one side, the say that arbitary channel\r\n * packets are allowed during kex exchange, on the other side we need to blindly\r\n * ignore the next _packet_ if the KEX guess was wrong. Where do we know from that\r\n * the next packet is not a channel data packet? Yes, we could check if it is in\r\n * the KEX range. But the standard says nothing about this. The OpenSSH guys\r\n * block local \"normal\" traffic during KEX. That's fine - however, they assume\r\n * that the other side is doing the same. During re-key, if they receive traffic\r\n * other than KEX, they become horribly irritated and kill the connection. Since\r\n * we are very likely going to communicate with OpenSSH servers, we have to play\r\n * the same game - even though we could do better.\r\n * \r\n * btw: having stdout and stderr on the same channel, with a shared window, is\r\n * also a VERY good idea... =(\r\n */\r\n\r\n/**\r\n * TransportManager.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: TransportManager.java,v 1.16 2006/08/11 12:24:00 cplattne Exp $\r\n */\r\npublic class TransportManager {\r\n    private static final Logger log = Logger.getLogger(TransportManager.class);\r\n    final Socket sock = new Socket();\r\n    private final Vector asynchronousQueue = new Vector();\r\n    String hostname;\r\n    int port;\r\n    Object connectionSemaphore = new Object();\r\n    boolean flagKexOngoing = false;\r\n    boolean connectionClosed = false;\r\n    Throwable reasonClosedCause = null;\r\n    TransportConnection tc;\r\n    KexManager km;\r\n    Vector messageHandlers = new Vector();\r\n    Thread receiveThread;\r\n    Vector connectionMonitors = new Vector();\r\n    boolean monitorsWereInformed = false;\r\n    private Thread asynchronousThread = null;\r\n\r\n    public TransportManager(String host, int port) throws IOException {\r\n        this.hostname = host;\r\n        this.port = port;\r\n    }\r\n\r\n    /**\r\n     * There were reports that there are JDKs which use\r\n     * the resolver even though one supplies a dotted IP\r\n     * address in the Socket constructor. That is why we\r\n     * try to generate the InetAdress \"by hand\".\r\n     *\r\n     * @param host\r\n     * @return the InetAddress\r\n     * @throws UnknownHostException\r\n     */\r\n    private InetAddress createInetAddress(String host) throws UnknownHostException {\r\n\t\t/* Check if it is a dotted IP4 address */\r\n\r\n        InetAddress addr = parseIPv4Address(host);\r\n\r\n        if (addr != null)\r\n            return addr;\r\n\r\n        return InetAddress.getByName(host);\r\n    }\r\n\r\n    private InetAddress parseIPv4Address(String host) throws UnknownHostException {\r\n        if (host == null)\r\n            return null;\r\n\r\n        String[] quad = Tokenizer.parseTokens(host, '.');\r\n\r\n        if ((quad == null) || (quad.length != 4))\r\n            return null;\r\n\r\n        byte[] addr = new byte[4];\r\n\r\n        for (int i = 0; i < 4; i++) {\r\n            int part = 0;\r\n\r\n            if ((quad[i].length() == 0) || (quad[i].length() > 3))\r\n                return null;\r\n\r\n            for (int k = 0; k < quad[i].length(); k++) {\r\n                char c = quad[i].charAt(k);\r\n\r\n\t\t\t\t/* No, Character.isDigit is not the same */\r\n                if ((c < '0') || (c > '9'))\r\n                    return null;\r\n\r\n                part = part * 10 + (c - '0');\r\n            }\r\n\r\n            if (part > 255) /* 300.1.2.3 is invalid =) */\r\n                return null;\r\n\r\n            addr[i] = (byte) part;\r\n        }\r\n\r\n        return InetAddress.getByAddress(host, addr);\r\n    }\r\n\r\n    public int getPacketOverheadEstimate() {\r\n        return tc.getPacketOverheadEstimate();\r\n    }\r\n\r\n    public void setTcpNoDelay(boolean state) throws IOException {\r\n        sock.setTcpNoDelay(state);\r\n    }\r\n\r\n    public void setSoTimeout(int timeout) throws IOException {\r\n        sock.setSoTimeout(timeout);\r\n    }\r\n\r\n    public ConnectionInfo getConnectionInfo(int kexNumber) throws IOException {\r\n        return km.getOrWaitForConnectionInfo(kexNumber);\r\n    }\r\n\r\n    public Throwable getReasonClosedCause() {\r\n        synchronized (connectionSemaphore) {\r\n            return reasonClosedCause;\r\n        }\r\n    }\r\n\r\n    public byte[] getSessionIdentifier() {\r\n        return km.sessionId;\r\n    }\r\n\r\n    public void close(Throwable cause, boolean useDisconnectPacket) {\r\n        if (useDisconnectPacket == false) {\r\n\t\t\t/* OK, hard shutdown - do not aquire the semaphore,\r\n\t\t\t * perhaps somebody is inside (and waits until the remote\r\n\t\t\t * side is ready to accept new data). */\r\n\r\n            try {\r\n                sock.close();\r\n            } catch (IOException ignore) {\r\n            }\r\n\r\n\t\t\t/* OK, whoever tried to send data, should now agree that\r\n\t\t\t * there is no point in further waiting =)\r\n\t\t\t * It is safe now to aquire the semaphore.\r\n\t\t\t */\r\n        }\r\n\r\n        synchronized (connectionSemaphore) {\r\n            if (connectionClosed == false) {\r\n                if (useDisconnectPacket == true) {\r\n                    try {\r\n                        byte[] msg = new PacketDisconnect(Packets.SSH_DISCONNECT_BY_APPLICATION, cause.getMessage(), \"\")\r\n                                .getPayload();\r\n                        if (tc != null)\r\n                            tc.sendMessage(msg);\r\n                    } catch (IOException ignore) {\r\n                    }\r\n\r\n                    try {\r\n                        sock.close();\r\n                    } catch (IOException ignore) {\r\n                    }\r\n                }\r\n\r\n                connectionClosed = true;\r\n                reasonClosedCause = cause; /* may be null */\r\n            }\r\n            connectionSemaphore.notifyAll();\r\n        }\r\n\r\n\t\t/* No check if we need to inform the monitors */\r\n\r\n        Vector monitors = null;\r\n\r\n        synchronized (this) {\r\n\t\t\t/* Short term lock to protect \"connectionMonitors\"\r\n\t\t\t * and \"monitorsWereInformed\"\r\n\t\t\t * (they may be modified concurrently)\r\n\t\t\t */\r\n\r\n            if (monitorsWereInformed == false) {\r\n                monitorsWereInformed = true;\r\n                monitors = (Vector) connectionMonitors.clone();\r\n            }\r\n        }\r\n\r\n        if (monitors != null) {\r\n            for (int i = 0; i < monitors.size(); i++) {\r\n                try {\r\n                    ConnectionMonitor cmon = (ConnectionMonitor) monitors.elementAt(i);\r\n                    cmon.connectionLost(reasonClosedCause);\r\n                } catch (Exception ignore) {\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    private void establishConnection(ProxyData proxyData, int connectTimeout) throws IOException {\r\n\t\t/* See the comment for createInetAddress() */\r\n\r\n        if (proxyData == null) {\r\n            InetAddress addr = createInetAddress(hostname);\r\n            sock.connect(new InetSocketAddress(addr, port), connectTimeout);\r\n            sock.setSoTimeout(0);\r\n            return;\r\n        }\r\n\r\n        if (proxyData instanceof HTTPProxyData) {\r\n            HTTPProxyData pd = (HTTPProxyData) proxyData;\r\n\r\n\t\t\t/* At the moment, we only support HTTP proxies */\r\n\r\n            InetAddress addr = createInetAddress(pd.proxyHost);\r\n            sock.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout);\r\n            sock.setSoTimeout(0);\r\n\r\n\t\t\t/* OK, now tell the proxy where we actually want to connect to */\r\n\r\n            StringBuffer sb = new StringBuffer();\r\n\r\n            sb.append(\"CONNECT \");\r\n            sb.append(hostname);\r\n            sb.append(':');\r\n            sb.append(port);\r\n            sb.append(\" HTTP/1.0\\r\\n\");\r\n\r\n            if ((pd.proxyUser != null) && (pd.proxyPass != null)) {\r\n                String credentials = pd.proxyUser + \":\" + pd.proxyPass;\r\n                char[] encoded = Base64.encode(credentials.getBytes());\r\n                sb.append(\"Proxy-Authorization: Basic \");\r\n                sb.append(encoded);\r\n                sb.append(\"\\r\\n\");\r\n            }\r\n\r\n            if (pd.requestHeaderLines != null) {\r\n                for (int i = 0; i < pd.requestHeaderLines.length; i++) {\r\n                    if (pd.requestHeaderLines[i] != null) {\r\n                        sb.append(pd.requestHeaderLines[i]);\r\n                        sb.append(\"\\r\\n\");\r\n                    }\r\n                }\r\n            }\r\n\r\n            sb.append(\"\\r\\n\");\r\n\r\n            OutputStream out = sock.getOutputStream();\r\n\r\n            out.write(sb.toString().getBytes());\r\n            out.flush();\r\n\r\n\t\t\t/* Now parse the HTTP response */\r\n\r\n            byte[] buffer = new byte[1024];\r\n            InputStream in = sock.getInputStream();\r\n\r\n            int len = ClientServerHello.readLineRN(in, buffer);\r\n\r\n            String httpReponse = new String(buffer, 0, len);\r\n\r\n            if (httpReponse.startsWith(\"HTTP/\") == false)\r\n                throw new IOException(\"The proxy did not send back a valid HTTP response.\");\r\n\r\n\t\t\t/* \"HTTP/1.X XYZ X\" => 14 characters minimum */\r\n\r\n            if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' '))\r\n                throw new IOException(\"The proxy did not send back a valid HTTP response.\");\r\n\r\n            int errorCode = 0;\r\n\r\n            try {\r\n                errorCode = Integer.parseInt(httpReponse.substring(9, 12));\r\n            } catch (NumberFormatException ignore) {\r\n                throw new IOException(\"The proxy did not send back a valid HTTP response.\");\r\n            }\r\n\r\n            if ((errorCode < 0) || (errorCode > 999))\r\n                throw new IOException(\"The proxy did not send back a valid HTTP response.\");\r\n\r\n            if (errorCode != 200) {\r\n                throw new HTTPProxyException(httpReponse.substring(13), errorCode);\r\n            }\r\n\r\n\t\t\t/* OK, read until empty line */\r\n\r\n            while (true) {\r\n                len = ClientServerHello.readLineRN(in, buffer);\r\n                if (len == 0)\r\n                    break;\r\n            }\r\n            return;\r\n        }\r\n\r\n        throw new IOException(\"Unsupported ProxyData\");\r\n    }\r\n\r\n    public void initialize(CryptoWishList cwl, ServerHostKeyVerifier verifier, DHGexParameters dhgex,\r\n                           int connectTimeout, SecureRandom rnd, ProxyData proxyData) throws IOException {\r\n\t\t/* First, establish the TCP connection to the SSH-2 server */\r\n\r\n        establishConnection(proxyData, connectTimeout);\r\n\r\n\t\t/* Parse the server line and say hello - important: this information is later needed for the\r\n\t\t * key exchange (to stop man-in-the-middle attacks) - that is why we wrap it into an object\r\n\t\t * for later use.\r\n\t\t */\r\n\r\n        ClientServerHello csh = new ClientServerHello(sock.getInputStream(), sock.getOutputStream());\r\n\r\n        tc = new TransportConnection(sock.getInputStream(), sock.getOutputStream(), rnd);\r\n\r\n        km = new KexManager(this, csh, cwl, hostname, port, verifier, rnd);\r\n        km.initiateKEX(cwl, dhgex);\r\n\r\n        receiveThread = new Thread(new Runnable() {\r\n            public void run() {\r\n                try {\r\n                    receiveLoop();\r\n                } catch (IOException e) {\r\n                    close(e, false);\r\n\r\n                    if (log.isEnabled())\r\n                        log.log(10, \"Receive thread: error in receiveLoop: \" + e.getMessage());\r\n                }\r\n\r\n                if (log.isEnabled())\r\n                    log.log(50, \"Receive thread: back from receiveLoop\");\r\n\r\n\t\t\t\t/* Tell all handlers that it is time to say goodbye */\r\n\r\n                if (km != null) {\r\n                    try {\r\n                        km.handleMessage(null, 0);\r\n                    } catch (IOException e) {\r\n                    }\r\n                }\r\n\r\n                for (int i = 0; i < messageHandlers.size(); i++) {\r\n                    HandlerEntry he = (HandlerEntry) messageHandlers.elementAt(i);\r\n                    try {\r\n                        he.mh.handleMessage(null, 0);\r\n                    } catch (Exception ignore) {\r\n                    }\r\n                }\r\n            }\r\n        });\r\n\r\n        receiveThread.setDaemon(true);\r\n        receiveThread.start();\r\n    }\r\n\r\n    public void registerMessageHandler(MessageHandler mh, int low, int high) {\r\n        HandlerEntry he = new HandlerEntry();\r\n        he.mh = mh;\r\n        he.low = low;\r\n        he.high = high;\r\n\r\n        synchronized (messageHandlers) {\r\n            messageHandlers.addElement(he);\r\n        }\r\n    }\r\n\r\n    public void removeMessageHandler(MessageHandler mh, int low, int high) {\r\n        synchronized (messageHandlers) {\r\n            for (int i = 0; i < messageHandlers.size(); i++) {\r\n                HandlerEntry he = (HandlerEntry) messageHandlers.elementAt(i);\r\n                if ((he.mh == mh) && (he.low == low) && (he.high == high)) {\r\n                    messageHandlers.removeElementAt(i);\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    public void sendKexMessage(byte[] msg) throws IOException {\r\n        synchronized (connectionSemaphore) {\r\n            if (connectionClosed) {\r\n                throw (IOException) new IOException(\"Sorry, this connection is closed.\").initCause(reasonClosedCause);\r\n            }\r\n\r\n            flagKexOngoing = true;\r\n\r\n            try {\r\n                tc.sendMessage(msg);\r\n            } catch (IOException e) {\r\n                close(e, false);\r\n                throw e;\r\n            }\r\n        }\r\n    }\r\n\r\n    public void kexFinished() throws IOException {\r\n        synchronized (connectionSemaphore) {\r\n            flagKexOngoing = false;\r\n            connectionSemaphore.notifyAll();\r\n        }\r\n    }\r\n\r\n    public void forceKeyExchange(CryptoWishList cwl, DHGexParameters dhgex) throws IOException {\r\n        km.initiateKEX(cwl, dhgex);\r\n    }\r\n\r\n    public void changeRecvCipher(BlockCipher bc, MAC mac) {\r\n        tc.changeRecvCipher(bc, mac);\r\n    }\r\n\r\n    public void changeSendCipher(BlockCipher bc, MAC mac) {\r\n        tc.changeSendCipher(bc, mac);\r\n    }\r\n\r\n    public void sendAsynchronousMessage(byte[] msg) throws IOException {\r\n        synchronized (asynchronousQueue) {\r\n            asynchronousQueue.addElement(msg);\r\n\r\n\t\t\t/* This limit should be flexible enough. We need this, otherwise the peer\r\n\t\t\t * can flood us with global requests (and other stuff where we have to reply\r\n\t\t\t * with an asynchronous message) and (if the server just sends data and does not\r\n\t\t\t * read what we send) this will probably put us in a low memory situation\r\n\t\t\t * (our send queue would grow and grow and...) */\r\n\r\n            if (asynchronousQueue.size() > 100)\r\n                throw new IOException(\"Error: the peer is not consuming our asynchronous replies.\");\r\n\r\n\t\t\t/* Check if we have an asynchronous sending thread */\r\n\r\n            if (asynchronousThread == null) {\r\n                asynchronousThread = new AsynchronousWorker();\r\n                asynchronousThread.setDaemon(true);\r\n                asynchronousThread.start();\r\n\r\n\t\t\t\t/* The thread will stop after 2 seconds of inactivity (i.e., empty queue) */\r\n            }\r\n        }\r\n    }\r\n\r\n    public void setConnectionMonitors(Vector monitors) {\r\n        synchronized (this) {\r\n            connectionMonitors = (Vector) monitors.clone();\r\n        }\r\n    }\r\n\r\n    public void sendMessage(byte[] msg) throws IOException {\r\n        if (Thread.currentThread() == receiveThread)\r\n            throw new IOException(\"Assertion error: sendMessage may never be invoked by the receiver thread!\");\r\n\r\n        synchronized (connectionSemaphore) {\r\n            while (true) {\r\n                if (connectionClosed) {\r\n                    throw (IOException) new IOException(\"Sorry, this connection is closed.\")\r\n                            .initCause(reasonClosedCause);\r\n                }\r\n\r\n                if (flagKexOngoing == false)\r\n                    break;\r\n\r\n                try {\r\n                    connectionSemaphore.wait();\r\n                } catch (InterruptedException e) {\r\n                }\r\n            }\r\n\r\n            try {\r\n                tc.sendMessage(msg);\r\n            } catch (IOException e) {\r\n                close(e, false);\r\n                throw e;\r\n            }\r\n        }\r\n    }\r\n\r\n    public void receiveLoop() throws IOException {\r\n        byte[] msg = new byte[35000];\r\n\r\n        while (true) {\r\n            int msglen = tc.receiveMessage(msg, 0, msg.length);\r\n\r\n            int type = msg[0] & 0xff;\r\n\r\n            if (type == Packets.SSH_MSG_IGNORE)\r\n                continue;\r\n\r\n            if (type == Packets.SSH_MSG_DEBUG) {\r\n                if (log.isEnabled()) {\r\n                    TypesReader tr = new TypesReader(msg, 0, msglen);\r\n                    tr.readByte();\r\n                    tr.readBoolean();\r\n                    StringBuffer debugMessageBuffer = new StringBuffer();\r\n                    debugMessageBuffer.append(tr.readString(\"UTF-8\"));\r\n\r\n                    for (int i = 0; i < debugMessageBuffer.length(); i++) {\r\n                        char c = debugMessageBuffer.charAt(i);\r\n\r\n                        if ((c >= 32) && (c <= 126))\r\n                            continue;\r\n                        debugMessageBuffer.setCharAt(i, '\\uFFFD');\r\n                    }\r\n\r\n                    log.log(50, \"DEBUG Message from remote: '\" + debugMessageBuffer.toString() + \"'\");\r\n                }\r\n                continue;\r\n            }\r\n\r\n            if (type == Packets.SSH_MSG_UNIMPLEMENTED) {\r\n                throw new IOException(\"Peer sent UNIMPLEMENTED message, that should not happen.\");\r\n            }\r\n\r\n            if (type == Packets.SSH_MSG_DISCONNECT) {\r\n                TypesReader tr = new TypesReader(msg, 0, msglen);\r\n                tr.readByte();\r\n                int reason_code = tr.readUINT32();\r\n                StringBuffer reasonBuffer = new StringBuffer();\r\n                reasonBuffer.append(tr.readString(\"UTF-8\"));\r\n\r\n\t\t\t\t/*\r\n\t\t\t\t * Do not get fooled by servers that send abnormal long error\r\n\t\t\t\t * messages\r\n\t\t\t\t */\r\n\r\n                if (reasonBuffer.length() > 255) {\r\n                    reasonBuffer.setLength(255);\r\n                    reasonBuffer.setCharAt(254, '.');\r\n                    reasonBuffer.setCharAt(253, '.');\r\n                    reasonBuffer.setCharAt(252, '.');\r\n                }\r\n\r\n\t\t\t\t/*\r\n\t\t\t\t * Also, check that the server did not send charcaters that may\r\n\t\t\t\t * screw up the receiver -> restrict to reasonable US-ASCII\r\n\t\t\t\t * subset -> \"printable characters\" (ASCII 32 - 126). Replace\r\n\t\t\t\t * all others with 0xFFFD (UNICODE replacement character).\r\n\t\t\t\t */\r\n\r\n                for (int i = 0; i < reasonBuffer.length(); i++) {\r\n                    char c = reasonBuffer.charAt(i);\r\n\r\n                    if ((c >= 32) && (c <= 126))\r\n                        continue;\r\n                    reasonBuffer.setCharAt(i, '\\uFFFD');\r\n                }\r\n\r\n                throw new IOException(\"Peer sent DISCONNECT message (reason code \" + reason_code + \"): \"\r\n                        + reasonBuffer.toString());\r\n            }\r\n\r\n\t\t\t/*\r\n\t\t\t * Is it a KEX Packet?\r\n\t\t\t */\r\n\r\n            if ((type == Packets.SSH_MSG_KEXINIT) || (type == Packets.SSH_MSG_NEWKEYS)\r\n                    || ((type >= 30) && (type <= 49))) {\r\n                km.handleMessage(msg, msglen);\r\n                continue;\r\n            }\r\n\r\n            MessageHandler mh = null;\r\n\r\n            for (int i = 0; i < messageHandlers.size(); i++) {\r\n                HandlerEntry he = (HandlerEntry) messageHandlers.elementAt(i);\r\n                if ((he.low <= type) && (type <= he.high)) {\r\n                    mh = he.mh;\r\n                    break;\r\n                }\r\n            }\r\n\r\n            if (mh == null)\r\n                throw new IOException(\"Unexpected SSH message (type \" + type + \")\");\r\n\r\n            mh.handleMessage(msg, msglen);\r\n        }\r\n    }\r\n\r\n    class HandlerEntry {\r\n        MessageHandler mh;\r\n        int low;\r\n        int high;\r\n    }\r\n\r\n    class AsynchronousWorker extends Thread {\r\n        public void run() {\r\n            while (true) {\r\n                byte[] msg = null;\r\n\r\n                synchronized (asynchronousQueue) {\r\n                    if (asynchronousQueue.size() == 0) {\r\n                        /* After the queue is empty for about 2 seconds, stop this thread */\r\n\r\n                        try {\r\n                            asynchronousQueue.wait(2000);\r\n                        } catch (InterruptedException e) {\r\n\t\t\t\t\t\t\t/* OKOK, if somebody interrupts us, then we may die earlier. */\r\n                        }\r\n\r\n                        if (asynchronousQueue.size() == 0) {\r\n                            asynchronousThread = null;\r\n                            return;\r\n                        }\r\n                    }\r\n\r\n                    msg = (byte[]) asynchronousQueue.remove(0);\r\n                }\r\n\r\n\t\t\t\t/* The following invocation may throw an IOException.\r\n\t\t\t\t * There is no point in handling it - it simply means\r\n\t\t\t\t * that the connection has a problem and we should stop\r\n\t\t\t\t * sending asynchronously messages. We do not need to signal that\r\n\t\t\t\t * we have exited (asynchronousThread = null): further\r\n\t\t\t\t * messages in the queue cannot be sent by this or any\r\n\t\t\t\t * other thread.\r\n\t\t\t\t * Other threads will sooner or later (when receiving or\r\n\t\t\t\t * sending the next message) get the same IOException and\r\n\t\t\t\t * get to the same conclusion.\r\n\t\t\t\t */\r\n\r\n                try {\r\n                    sendMessage(msg);\r\n                } catch (IOException e) {\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/util/PasswordField.java",
    "content": "package ch.ethz.ssh2.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PushbackInputStream;\nimport java.util.Arrays;\n\n/**\n * This class prompts the user for a password and attempts to mask input with \"*\"\n */\n\npublic class PasswordField {\n\n    /**\n     * @param in  stream to be used (e.g. System.in)\n     * @param prompt The prompt to display to the user.\n     * @return The password as entered by the user.\n     */\n\n    public static final char[] getPassword(InputStream in, String prompt) throws IOException {\n        MaskingThread maskingthread = new MaskingThread(prompt);\n        Thread thread = new Thread(maskingthread);\n        thread.start();\n\n        char[] lineBuffer;\n        char[] buf;\n        int i;\n\n        buf = lineBuffer = new char[128];\n\n        int room = buf.length;\n        int offset = 0;\n        int c;\n\n        loop:\n        while (true) {\n            switch (c = in.read()) {\n                case -1:\n                case '\\n':\n                    break loop;\n\n                case '\\r':\n                    int c2 = in.read();\n                    if ((c2 != '\\n') && (c2 != -1)) {\n                        if (!(in instanceof PushbackInputStream)) {\n                            in = new PushbackInputStream(in);\n                        }\n                        ((PushbackInputStream) in).unread(c2);\n                    } else {\n                        break loop;\n                    }\n\n                default:\n                    if (--room < 0) {\n                        buf = new char[offset + 128];\n                        room = buf.length - offset - 1;\n                        System.arraycopy(lineBuffer, 0, buf, 0, offset);\n                        Arrays.fill(lineBuffer, ' ');\n                        lineBuffer = buf;\n                    }\n                    buf[offset++] = (char) c;\n                    break;\n            }\n        }\n        maskingthread.stopMasking();\n        if (offset == 0) {\n            return null;\n        }\n        char[] ret = new char[offset];\n        System.arraycopy(buf, 0, ret, 0, offset);\n        Arrays.fill(buf, ' ');\n        return ret;\n    }\n\n    /**\n     * This class attempts to erase characters echoed to the console.\n     */\n    /**\n     * This class attempts to erase characters echoed to the console.\n     */\n    static class MaskingThread extends Thread {\n        private volatile boolean stop = false;\n\n        private int index;\n\n        private String prompt;\n\n        /**\n         * @param prompt The prompt displayed to the user\n         */\n        public MaskingThread(String prompt) {\n            this.prompt = prompt;\n        }\n\n        /**\n         * Begin masking until asked to stop.\n         */\n        public void run() {\n            int priority = Thread.currentThread().getPriority();\n            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);\n            try {\n                while (!stop) {\n                    try {\n                        // attempt masking at this rate\n                        Thread.sleep(2);\n                    } catch (InterruptedException iex) {\n                        iex.printStackTrace();\n                    }\n\n                    if (!stop) {\n                        System.out.print(\"\\r\" + prompt + \" \\r\" + prompt);\n                        System.out.flush();\n                    }\n                }\n            } finally { // restore the original priority\n                Thread.currentThread().setPriority(priority);\n            }\n        }\n\n        /**\n         * Instruct the thread to stop masking.\n         */\n        public void stopMasking() {\n            this.stop = true;\n        }\n    }\n}"
  },
  {
    "path": "src/ch/ethz/ssh2/util/PasswordReader.java",
    "content": "package ch.ethz.ssh2.util;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\n\npublic class PasswordReader {\n    public static String readPassword(String prompt) {\n        System.out.print(prompt);\n        try {\n            return String.valueOf(System.console().readPassword());\n        } catch (Throwable t) {\n            //java <1.6\n            try {\n                BufferedReader in = new BufferedReader(new InputStreamReader(System.in));\n                return in.readLine();\n            } catch (IOException e) {\n                return null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/ch/ethz/ssh2/util/TimeoutService.java",
    "content": "package ch.ethz.ssh2.util;\r\n\r\nimport ch.ethz.ssh2.log.Logger;\r\n\r\nimport java.io.PrintWriter;\r\nimport java.io.StringWriter;\r\nimport java.util.Collections;\r\nimport java.util.LinkedList;\r\n\r\n/**\r\n * TimeoutService (beta). Here you can register a timeout.\r\n * <p>\r\n * Implemented having large scale programs in mind: if you open many concurrent SSH connections\r\n * that rely on timeouts, then there will be only one timeout thread. Once all timeouts\r\n * have expired/are cancelled, the thread will (sooner or later) exit.\r\n * Only after new timeouts arrive a new thread (singleton) will be instantiated.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: TimeoutService.java,v 1.2 2006/07/30 21:59:29 cplattne Exp $\r\n */\r\npublic class TimeoutService {\r\n    private static final Logger log = Logger.getLogger(TimeoutService.class);\r\n    /* The list object is also used for locking purposes */\r\n    private static final LinkedList todolist = new LinkedList();\r\n    private static Thread timeoutThread = null;\r\n\r\n    /**\r\n     * It is assumed that the passed handler will not execute for a long time.\r\n     *\r\n     * @param runTime\r\n     * @param handler\r\n     * @return a TimeoutToken that can be used to cancel the timeout.\r\n     */\r\n    public static final TimeoutToken addTimeoutHandler(long runTime, Runnable handler) {\r\n        TimeoutToken token = new TimeoutToken(runTime, handler);\r\n\r\n        synchronized (todolist) {\r\n            todolist.add(token);\r\n            Collections.sort(todolist);\r\n\r\n            if (timeoutThread != null)\r\n                timeoutThread.interrupt();\r\n            else {\r\n                timeoutThread = new TimeoutThread();\r\n                timeoutThread.setDaemon(true);\r\n                timeoutThread.start();\r\n            }\r\n        }\r\n\r\n        return token;\r\n    }\r\n\r\n    public static final void cancelTimeoutHandler(TimeoutToken token) {\r\n        synchronized (todolist) {\r\n            todolist.remove(token);\r\n\r\n            if (timeoutThread != null)\r\n                timeoutThread.interrupt();\r\n        }\r\n    }\r\n\r\n    public static class TimeoutToken implements Comparable {\r\n        private long runTime;\r\n        private Runnable handler;\r\n\r\n        private TimeoutToken(long runTime, Runnable handler) {\r\n            this.runTime = runTime;\r\n            this.handler = handler;\r\n        }\r\n\r\n        public int compareTo(Object o) {\r\n            TimeoutToken t = (TimeoutToken) o;\r\n            if (runTime > t.runTime)\r\n                return 1;\r\n            if (runTime == t.runTime)\r\n                return 0;\r\n            return -1;\r\n        }\r\n    }\r\n\r\n    private static class TimeoutThread extends Thread {\r\n        public void run() {\r\n            synchronized (todolist) {\r\n                while (true) {\r\n                    if (todolist.size() == 0) {\r\n                        timeoutThread = null;\r\n                        return;\r\n                    }\r\n\r\n                    long now = System.currentTimeMillis();\r\n\r\n                    TimeoutToken tt = (TimeoutToken) todolist.getFirst();\r\n\r\n                    if (tt.runTime > now) {\r\n                        /* Not ready yet, sleep a little bit */\r\n\r\n                        try {\r\n                            todolist.wait(tt.runTime - now);\r\n                        } catch (InterruptedException e) {\r\n                        }\r\n\r\n\t\t\t\t\t\t/* We cannot simply go on, since it could be that the token\r\n\t\t\t\t\t\t * was removed (cancelled) or another one has been inserted in\r\n\t\t\t\t\t\t * the meantime.\r\n\t\t\t\t\t\t */\r\n\r\n                        continue;\r\n                    }\r\n\r\n                    todolist.removeFirst();\r\n\r\n                    try {\r\n                        tt.handler.run();\r\n                    } catch (Exception e) {\r\n                        StringWriter sw = new StringWriter();\r\n                        e.printStackTrace(new PrintWriter(sw));\r\n                        log.log(20, \"Exeception in Timeout handler:\" + e.getMessage() + \"(\" + sw.toString() + \")\");\r\n                    }\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/ch/ethz/ssh2/util/Tokenizer.java",
    "content": "package ch.ethz.ssh2.util;\r\n\r\n/**\r\n * Tokenizer. Why? Because StringTokenizer is not available in J2ME.\r\n *\r\n * @author Christian Plattner, plattner@inf.ethz.ch\r\n * @version $Id: Tokenizer.java,v 1.1 2005/12/05 17:13:27 cplattne Exp $\r\n */\r\npublic class Tokenizer {\r\n    /**\r\n     * Exists because StringTokenizer is not available in J2ME.\r\n     * Returns an array with at least 1 entry.\r\n     *\r\n     * @param source    must be non-null\r\n     * @param delimiter\r\n     * @return an array of Strings\r\n     */\r\n    public static String[] parseTokens(String source, char delimiter) {\r\n        int numtoken = 1;\r\n\r\n        for (int i = 0; i < source.length(); i++) {\r\n            if (source.charAt(i) == delimiter)\r\n                numtoken++;\r\n        }\r\n\r\n        String list[] = new String[numtoken];\r\n        int nextfield = 0;\r\n\r\n        for (int i = 0; i < numtoken; i++) {\r\n            if (nextfield >= source.length()) {\r\n                list[i] = \"\";\r\n            } else {\r\n                int idx = source.indexOf(delimiter, nextfield);\r\n                if (idx == -1)\r\n                    idx = source.length();\r\n                list[i] = source.substring(nextfield, idx);\r\n                nextfield = idx + 1;\r\n            }\r\n        }\r\n\r\n        return list;\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/Config.java",
    "content": "package edu.caltech.hep.dcapj;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.Enumeration;\nimport java.util.Properties;\nimport java.util.logging.Logger;\n\n/**\n * This class contains configuration information for dCapJ. The default values\n * can be overridden by setting the environment variable\n * <code>DCAPJ_CONFIG_FILE</code> to the absolute path of the file.\n *\n * @author Kamran Soomro\n * @author Faisal Khan\n */\n\npublic class Config {\n    private Logger _logger = Logger.getLogger(Config.class.getName());\n\n    private String _nic = null;\n\n    // host name of form host:port\n    private String _dCapDoor = null;\n    private String _pnfsDir = null;\n\n    // default in seconds\n    private int _poolTimeout = 5;\n\n    /**\n     * Create an instance.\n     * <p>\n     * If the <code>DCAPJ_CONFIG_FILE</code> variable is defined, the values\n     * defined in the file override the default values.\n     */\n    public Config() {\n        initialize();\n    }\n\n    private void initialize() {\n        String dCapConf = null;\n        try {\n            dCapConf = System.getenv(\"DCAPJ_CONFIG_FILE\");\n            if (dCapConf != null) {\n                _logger\n                        .info(\"DCAPJ_CONFIG_FILE environment variable is define; configuration from \"\n                                + \" this file will take precedence over default values\");\n            } else {\n                _logger.info(\"No post-configuration file for dCapJ\");\n                return;\n            }\n\n            File propFile = new File(dCapConf);\n            if (propFile.exists()) {\n                Properties prop = new Properties();\n                prop.load(new FileInputStream(propFile));\n\n                _logger.info(\"Loaded dCap conf file \" + dCapConf);\n\n                // extracting desired configuration\n                _pnfsDir = prop.getProperty(\"pnfs.dir\");\n                _logger.fine(\"Config: pnfs dir = \" + _pnfsDir);\n\n                _dCapDoor = prop.getProperty(\"dcapdoor.hostname\");\n                _logger.fine(\"Config: dCap host = \" + _dCapDoor);\n\n                _nic = prop.getProperty(\"interface\");\n                _logger.fine(\"Config: local interface = \" + _nic);\n\n                String tmp = prop.getProperty(\"poolTimeout\", \"5\");\n                try {\n                    _poolTimeout = Integer.parseInt(tmp);\n                } catch (Exception e) {\n                    _poolTimeout = 5;\n                }\n                _logger.fine(\"Config: pool timeout = \" + _poolTimeout);\n\n            } else {\n                _logger.warning(\"dCap configuration file doesn't exist \"\n                        + dCapConf);\n            }\n        } catch (Exception e) {\n            _logger\n                    .info(\"Unable to load configuration file; default values will be used\");\n            // _logger.throwing(e);\n        }\n    }\n\n    /**\n     * Get the Pnfs ID of the file.\n     *\n     * @return The Pnfs ID of the file.\n     */\n    public String getPnfsDir() {\n        return _pnfsDir;\n    }\n\n    /**\n     * Get the location of the dCap door.\n     *\n     * @return The location of the dCap door of the form <i>hostname:port</i>\n     */\n    public String getdCapDoor() {\n        return _dCapDoor;\n    }\n\n    /**\n     * Get the interface to use for receiving callback connections from pools.\n     *\n     * @return The IP address of the interface to use for callback connections.\n     */\n    public String getInterface() {\n        if (_nic != null)\n            return _nic;\n\n        try {\n            Enumeration<NetworkInterface> nics = NetworkInterface\n                    .getNetworkInterfaces();\n            while (nics.hasMoreElements()) {\n                NetworkInterface nic = nics.nextElement();\n                Enumeration<InetAddress> ips = nic.getInetAddresses();\n                while (ips.hasMoreElements()) {\n                    InetAddress ip = ips.nextElement();\n                    if (!ip.isLoopbackAddress() && ip instanceof Inet4Address) {\n                        _nic = ip.getHostAddress();\n                        return _nic;\n                    }\n                }\n            }\n        } catch (Exception ex) {\n        }\n\n        return null;\n    }\n\n    /**\n     * Get the time to wait for a pool to respond.\n     *\n     * @return The pool timeout.\n     */\n    public int getPoolTimeout() {\n        return _poolTimeout;\n    }\n\n    /**\n     * Set the time to wait for a pool to respond.\n     *\n     * @param timeout The pool timeout in seconds.\n     */\n    public void setPoolTimeout(int timeout) {\n        _poolTimeout = timeout;\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/PnfsUtil.java",
    "content": "/**\n * A utility class for extracting useful information\n * from the pnfs filesystem by reading pnfs files.\n *\n * @author Faisal Khan\n * @version 0.1\n */\n\npackage edu.caltech.hep.dcapj;\n\nimport java.io.*;\nimport java.util.Vector;\n\npublic class PnfsUtil {\n\n    /** Enables/disables debug mode. */\n    public static boolean DEBUG = false;\n    private static String PATH_SEPARATOR = \"/\";\n\n    /**\n     * PNFS ID is extracted by reading .(id)(filename) under the parent directory of\n     * the given path.\n     */\n    public static String getPnfsID(String path) throws FileNotFoundException,\n            IOException {\n\n        File pnfsPath = new File(path);\n        File dir = pnfsPath.getParentFile();\n\n        if (!dir.isDirectory())\n            throw new FileNotFoundException(\n                    \"Invalid pnfs path: Unable to extract parent directory\");\n\n        //fomat = /path-to-pnfs file-parents directory/.(id)(pnfs-file-name)\n        String pnfslayer = dir.getPath() + \"\" + PATH_SEPARATOR + \".(id)(\"\n                + pnfsPath.getName() + \")\";\n\n        if (DEBUG)\n            System.err.println(\"Reading pnfslayer's file: \" + pnfslayer);\n\n        FileInputStream fis = new FileInputStream(pnfslayer);\n        byte idbytes[] = new byte[1024];\n        int rcount = fis.read(idbytes);\n\n        if (DEBUG)\n            System.out.println(\"Number of bytes read = \" + rcount);\n\n        if (rcount < 0)\n            throw new IOException(\"Couldn't read pnfslayer file \" + pnfslayer);\n\n        return new String(idbytes).trim();\n    }\n\n    /**\n     * Check whether a given path is a valid PNFS path.\n     * @param path The path to check.\n     * @return <code>true</code> if the path is a valid PNFS path, <code>false</code> otherwise.\n     */\n    public static boolean isPnfs(String path) {\n        File pnfsPath = new File(path);\n        File dir = pnfsPath.getParentFile();\n\n        //file/path should exist as the remaining test are based on directory.\n        if (!pnfsPath.exists()) {\n            if (DEBUG)\n                System.out.println(\"Requested path or file doesn't exist. \" + pnfsPath);\n\n            return false;\n        }\n\n        if (!dir.isDirectory()) {\n            if (DEBUG)\n                System.out\n                        .println(\"Invalid pnfs path: Unable to extract parent directory\");\n            return false;\n        }\n\n        //format = /path-to-pnfs-file's parent direcoty/.(get)(cursor)\n        String pnfslayer = dir.getPath() + \"\" + PATH_SEPARATOR\n                + \".(get)(cursor)\";\n\n        if (DEBUG)\n            System.err.println(\"Checking  pnfslayer's file: \" + pnfslayer);\n\n        File fpnfslayer = new File(pnfslayer);\n        //if the pnfs layer file exists and we can read it\n        //it means it is pnfs file system.\n        if (fpnfslayer.exists() && fpnfslayer.canRead())\n            return true;\n        else\n            return false;\n    }\n\n    /**\n     * Get all dCap doors from the PNFS server.\n     * @param path The PNFS path.\n     * @return The addresses of the dCap doors in a <code>String</code> array.\n     * @throws FileNotFoundException If the path is invalid.\n     * @throws IOException If there was an error getting the dCap doors.\n     */\n    public static String[] getdCapDoors(String path)\n            throws FileNotFoundException, IOException {\n\n        File pnfsfile = new File(path);\n        File dir = pnfsfile.getParentFile();\n\n        if (DEBUG) {\n            System.out.println(\"Querying dCache's door for pnfs path \" + path);\n            System.out.println(\"Checking if it is pnfs path\");\n\n        }\n\n        //path should exist and it should belong to pnfs layer.\n        if (!isPnfs(path)) {\n\n            if (DEBUG)\n                System.out.println(\"Not a valid pnfs path : \" + path);\n\n            return null;\n        }\n\n        //It's a pnfs path, going to read the conf file for getting list of\n        //dcache's file.\n        String pnfslayer = dir.getPath() + PATH_SEPARATOR\n                + \".(config)(dCache)/dcache.conf\";\n\n        if (DEBUG)\n            System.out.println(\"Reading pnfs layer file \" + pnfslayer);\n\n        File fpnfslayer = new File(pnfslayer);\n        if (!fpnfslayer.exists() || !fpnfslayer.canRead()) {\n            throw new IOException(\"Unable to read pnfs layer file \" + pnfslayer);\n        }\n\n        BufferedReader buffreader = new BufferedReader(\n                new FileReader(pnfslayer));\n\n        String line = null;\n        Vector<String> hosts = new Vector<String>();\n        while ((line = buffreader.readLine()) != null) {\n            hosts.add(line);\n\n            if (DEBUG)\n                System.out.println(\"Host = \" + line);\n        }\n\n        if (DEBUG)\n            System.out\n                    .println(\"Number of doors available are  \" + hosts.size());\n\n        return hosts.toArray(new String[0]);\n    }\n\n    /**\n     * Get random PNFS door from the PNFS server.\n     * @param pnfspath The PNFS path.\n     * @return Address of random PNFS door.\n     * @throws FileNotFoundException If the path is invalid.\n     * @throws IOException If there was an error getting the dCap doors.\n     */\n    public static String getdCapDoor(String pnfspath)\n            throws FileNotFoundException, IOException {\n\n        String selectedHost = null;\n\n        String[] hosts = getdCapDoors(pnfspath);\n        //First get the list of all available doors and then\n        //pick one at random. Almost the same mechanism as adopted\n        //by dcap.\n        if (hosts.length == 1)\n            selectedHost = hosts[0];\n        else if (hosts.length > 1) {\n            //more than 1 hosts. Let's pick one at random\n            int random = (int) Math.random() * hosts.length;\n            if (random > 0 && random < hosts.length) {\n                if (DEBUG)\n                    System.out.println(\"Picking \" + hosts[random]\n                            + \" at random \");\n                selectedHost = hosts[random];\n\n            } else {\n                if (DEBUG) //this shouldn't happen\n                    System.out.println(\"dCap host selection failed; unable to precicesly calculate\" +\n                            \" random number.\");\n            }\n        }\n        return selectedHost;\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/dCacheFile.java",
    "content": "package edu.caltech.hep.dcapj;\n\nimport edu.caltech.hep.dcapj.util.*;\n\nimport java.io.*;\nimport java.nio.BufferOverflowException;\nimport java.nio.BufferUnderflowException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.SocketChannel;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Main class that implements all the file-like behaviour for dCache files.\n * <p>\n * Although all the read and write functions are implemented in this class, it\n * is not recommended to use them. To open a file for IO, use\n * {@link edu.caltech.hep.dcapj.io.dCacheFileOutputStream} and\n * {@link edu.caltech.hep.dcapj.io.dCacheFileInputStream}. To achieve NIO like\n * functionality, use {@link edu.caltech.hep.dcapj.nio.dCacheFileChannel}.\n *\n * @author Kamran Soomro\n * @author Faisal Khan\n */\npublic class dCacheFile extends File implements DataConnectionCallback,\n        ControlCommandCallback {\n\n    protected SocketChannel _clientChannel = null;\n    private Logger _logger = Logger.getLogger(dCacheFile.class.getName());\n    private boolean _connected = false;\n    private boolean _poolReplied = false;\n    private boolean _doorReplied = false;\n    private ByteBuffer _commandBuffer = null;\n    private IOCallback _poolCallback = null;\n    private ControlConnection _controlConnection = null;\n    private String _pnfsID;\n    private int _sessionID = -1;\n    private int _commandID = -1;\n    private Mode _openMode;\n\n    ;\n    private long _max_bytes = Long.MAX_VALUE;\n    private boolean _writable = false;\n    private long _filesize;\n    private int _poolID = 0;\n    private int _mode;\n    private SelectionKey _selectionKey;\n    private String[] _doorReply = null;\n\n    /*\n     * private int _uid; private int _guid;\n     * \n     * private long _atime; private long _mtime; private long _ctime;\n     */\n\n    public dCacheFile(String name, String openMode) throws FileNotFoundException,\n            IOException, InvalidConfigurationException {\n        this(name, openMode.equals(\"w\") ? Mode.WRITE_ONLY : Mode.READ_ONLY);\n    }\n\n    /**\n     * Create a dCacheFile.\n     *\n     * @param name     Path of the file to open. The path should be absolute.\n     * @param openMode Open the file in read or write mode.\n     * @throws FileNotFoundException         If the file is not found\n     * @throws IOException                   If there was an error opening/creating the file\n     * @throws InvalidConfigurationException If the <code>$DCAPJ_CONFIG_FILE</code> is in an invalid\n     *                                       format\n     */\n    public dCacheFile(String name, Mode openMode) throws FileNotFoundException,\n            IOException, InvalidConfigurationException {\n        super(name);\n\n        // if dcap layer is not initialized, don't do anything\n        if (!dCapLayer.isInitialized()) {\n            throw new InvalidConfigurationException(\n                    \"dCap layer should be initialized by \"\n                            + \"  making a call to dCapLayer.initialze()\");\n        }\n\n        // We can only handle files that are part of dCache.\n        _openMode = openMode;\n        _logger.fine(\"[\" + name + \"] mode \" + _openMode);\n\n        _poolCallback = dCapLayer.getDataConnectionCallback();\n        _controlConnection = dCapLayer.getControlConnection();\n\n        _sessionID = _controlConnection.getNextSessionID();\n        _logger.fine(\"[\" + name + \"] sessionID = \" + _sessionID);\n\n        _controlConnection.registerCallback(_sessionID, this);\n        _logger.finer(\"[\" + name + \"] registered callback with sessionID \"\n                + _sessionID);\n\n        if (!super.exists()) {\n            if (_openMode == Mode.WRITE_ONLY) {\n                if (super.createNewFile())\n                    _logger.fine(\"Created new file \" + super.getName());\n            } else // _openMode == Mode.READ_ONLY\n            {\n                FileNotFoundException ex = new FileNotFoundException(\n                        \"File does not exist \" + name);\n                _logger.throwing(\"dCacheFile\", \"dCacheFile(String)\", ex);\n                throw ex;\n            }\n        } else // File exists\n        {\n            if (_openMode == Mode.WRITE_ONLY) {\n                IOException ex = new IOException(\"File already exists\");\n                _logger.throwing(\"dCacheFile\", \"dCacheFile(String)\", ex);\n                throw ex;\n            }\n        } // File exists and we want to read\n\n        _pnfsID = PnfsUtil.getPnfsID(super.getAbsolutePath()); // getPnfsID();\n        if (_openMode == Mode.READ_ONLY) {\n            this.open();\n            this.tell();\n            _connected = true;\n            getPoolID();\n        }\n    }\n\n    private void open() throws IOException {\n        _logger.log(Level.FINE, \"Opening file \" + this.getAbsolutePath());\n\n        boolean result = false;\n\n        result = _poolCallback.registerCallback(_sessionID, this);\n\n        if (!result) {\n            String emsg = \"Open failed on file \" + getName()\n                    + \"; Unable to register \" + \" pool call back for session \"\n                    + _sessionID;\n            _logger.severe(emsg);\n            throw new IOException(emsg);\n        }\n\n        String mode = (_openMode == Mode.READ_ONLY) ? \"\\\"r\\\"\" : \"\\\"w\\\"\";\n\n        String ip = dCapLayer.getConfig().getInterface();\n        if (ip == null) {\n            IOException ex = new IOException(\n                    \"Cannot get ip address for system.\");\n            _logger.severe(ex.getMessage());\n            _logger.throwing(\"dCacheFile\", \"open\", ex);\n            throw ex;\n        }\n\n        _doorReplied = false;\n        String openCommand = _sessionID + \" \" + (++_commandID)\n                + \" client open \" + _pnfsID + \" \" + mode + \" \" + ip + \" \"\n                + _poolCallback.getPort();\n        _controlConnection.sendCommand(openCommand);\n\n        long t0 = System.currentTimeMillis();\n        int poolTimeout = dCapLayer.getConfig().getPoolTimeout();\n        _logger.finest(\"Pool timeout value is set as \" + poolTimeout + \" secs\");\n\n        // Wait here until\n        // (a) door comes back to us with an error\n        // (b) pool timeout value is reached\n        // (c) pool replies with the connection\n        while (!_doorReplied\n                && ((System.currentTimeMillis() - t0) < (poolTimeout * 1000))\n                && !_poolReplied) {\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException ex) {\n                _logger.finer(\"Thread was interrupted while\"\n                        + \" waiting for door reply\");\n            }\n            _logger.finest(\"Waiting for a reply from pool for\"\n                    + super.getName());\n        }\n\n        if (_doorReplied) {\n            String reply = \"\";\n            for (String replyPart : _doorReply)\n                reply += replyPart + \" \";\n            String errormsg = \"dCapJ \" + reply;\n            _logger.severe(errormsg);\n            throw new IOException(errormsg);\n        }\n        // clear door reply status\n        _doorReplied = false;\n\n        _logger.fine(\"Waiting for a data call back connection\");\n        long t1 = System.currentTimeMillis();\n        while (!_poolReplied) {\n\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException ex) {\n                _logger.finer(\"Thread was interrupted \"\n                        + \"while waiting for pool reply\");\n            }\n\n            _logger.finest(\"Waiting for a reply from pool for\"\n                    + super.getName());\n\n            if ((System.currentTimeMillis() - t1) > (poolTimeout * 1000)) {\n                _logger.severe(\"Pool wait timedout!\");\n                throw new IOException(\"No reply from pool within give time\");\n            }\n        }\n\n        _logger.info(\"Pool connected for file: \" + super.getName());\n\n        // Receive Mover HELLO BLOCK\n        ByteBuffer commandBuffer = ByteBuffer.allocate(20);\n        commandBuffer.limit(4);\n\n        _clientChannel.read(commandBuffer);\n\n        commandBuffer.rewind();\n        int nBytes = commandBuffer.getInt();\n        if (nBytes > 0) {\n            commandBuffer.limit(nBytes);\n            commandBuffer.rewind();\n            _clientChannel.read(commandBuffer);\n\n            byte utf[] = new byte[commandBuffer.remaining()];\n            commandBuffer.get(utf);\n            String reply = new String(utf);\n            _logger.severe(\"Error receiving HELLO BLOCK.\" + reply);\n            throw new IOException(\"Unknown error receiving HELLO BLOCK\");\n        }\n\n        _logger.fine(\"Received HELLO BLOCK [sessionID = \" + _sessionID\n                + \", nBytes = \" + nBytes);\n    }\n\n    /**\n     * Set the cursor to the specified offset. This method is only available if\n     * the file is opened for reading.\n     * *\n     *\n     * @param offset   The offset within the file to set the cursor to\n     * @param relative If true, the offset is calculated from the current position\n     *                 within the file, otherwise it is calculated as absolute\n     * @return The new position\n     * @throws IOException If there was an error setting the cursor\n     */\n    public long seek(long offset, boolean relative) throws IOException {\n        if (_openMode == Mode.WRITE_ONLY) {\n            IOException ex = new IOException(\"Cannot seek in WRITE mode.\");\n            _logger.throwing(\"dCacheFile\", \"seek\", ex);\n        }\n\n        _logger.fine(\"Sending SEEK command to pool [offset = \" + offset\n                + \", relative = \" + relative + \"]\");\n\n        ByteBuffer _commandBuffer = ByteBuffer.allocate(30);\n\n        _commandBuffer.putInt(16);\n        _commandBuffer.putInt(3);\n        _commandBuffer.putLong(offset);\n\n        _commandBuffer.flip();\n        _clientChannel.write(_commandBuffer);\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(4);\n        if (offset >= 0)\n            if (relative) // From current position\n                _commandBuffer.putInt(1);\n            else\n                _commandBuffer.putInt(0);\n        else if (offset < 0) // From end of file\n            _commandBuffer.putInt(2);\n\n        _clientChannel.write(_commandBuffer);\n\n        _commandBuffer.clear();\n        _commandBuffer.limit(16);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        int nBytes = _commandBuffer.getInt();\n        int ack = _commandBuffer.getInt();\n        int cmdCode = _commandBuffer.getInt();\n        int success = _commandBuffer.getInt();\n\n        if (success != 0) // Command failed\n        {\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n\n            _logger.severe(\"SEEK command failed [nBytes = \" + nBytes\n                    + \", ack = \" + ack + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success + \"]\\n\" + \"Pool replied: \"\n                    + detail);\n\n            IOException ex = new IOException(detail);\n            _logger.throwing(\"dCacheFile\", \"seek\", ex);\n            throw ex;\n        }\n\n        // Command succeeded\n        _logger.fine(\"SEEK succeeded [nBytes = \" + nBytes + \", ack = \" + ack\n                + \", cmdCode = \" + cmdCode + \", success = \" + success + \"]\");\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(8);\n        _clientChannel.read(_commandBuffer);\n\n        return _commandBuffer.getLong();\n    }\n\n    // TODO: Let's see what we can do for stat\n    /*\n     * private void stat() throws IOException { _poolOut.writeInt(4);\n     * _poolOut.writeInt(10); // Send STATUS command\n     * \n     * int nBytes = _poolIn.readInt() - 12; // Should be 12 int ack =\n     * _poolIn.readInt(); int cmdCode = _poolIn.readInt(); int success =\n     * _poolIn.readInt();\n     * \n     * if (success != 0) // Means command failed { String detail =\n     * _poolIn.readUTF(); _logger.severe(\"Cannot get STATUS information for file\n     * [nBytes = \" + nBytes + \", ack = \" + ack + \", cmdCode = \" + cmdCode + \",\n     * success = \" + success + \"]\\n\" + \"Pool replied: \" + detail);\n     * \n     * IOException ex = new IOException(detail); _logger.throwing(\"dCacheFile\",\n     * \"stat\", ex); throw ex; } // Else if command successful _mode =\n     * _poolIn.readInt(); int nLinks = _poolIn.readInt();\n     * \n     * _uid = _poolIn.readInt(); _guid = _poolIn.readInt(); _filesize =\n     * _poolIn.readLong(); _atime = _poolIn.readLong(); _mtime =\n     * _poolIn.readLong(); _ctime = _poolIn.readLong(); }\n     */\n\n    /**\n     * Get the current position of the cursor.\n     * <p>\n     * Only available if the file is opened for reading.\n     *\n     * @return The current position of the cursor in the file\n     * @throws IOException If there was an error getting the cursor\n     */\n    public long tell() throws IOException {\n        if (_openMode == Mode.WRITE_ONLY) {\n            IOException ex = new IOException(\"Cannot get cursor position in WRITE mode\");\n            _logger.throwing(\"dCacheFiles\", \"tell\", ex);\n            throw ex;\n        }\n\n        _logger.fine(\"Sending LOCATE command to pool\");\n\n        ByteBuffer _commandBuffer = ByteBuffer.allocate(30);\n\n        _commandBuffer.putInt(4);\n        _commandBuffer.putInt(9);\n\n        _commandBuffer.flip();\n        _clientChannel.write(_commandBuffer);\n\n        _commandBuffer.clear();\n        _commandBuffer.limit(4);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        int nBytes = _commandBuffer.getInt();\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(nBytes);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        int ack = _commandBuffer.getInt();// Should be 28\n        int cmdCode = _commandBuffer.getInt(); // Should be 9\n        int success = _commandBuffer.getInt();\n\n        if (success != 0) // Command failed\n        {\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n\n            _logger.severe(\"LOCATE command failed [nBytes = \" + nBytes\n                    + \", ack = \" + ack + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success + \"]\\n\" + \"Pool replied: \"\n                    + detail);\n\n            IOException ex = new IOException(detail);\n            _logger.throwing(\"dCacheFile\", \"tell\", ex);\n            throw ex;\n        }\n\n        // Command succeeded\n        _logger.fine(\"LOCATE succeeded [nBytes = \" + nBytes + \", ack = \" + ack\n                + \", cmdCode = \" + cmdCode + \", success = \" + success + \"]\");\n\n        _filesize = _commandBuffer.getLong();\n\n        return _commandBuffer.getLong();\n    }\n\n    /**\n     * Read from the file.\n     *\n     * @param bytes Fill the buffer <i>bytes</i> with bytes from the file\n     * @param off   The offset within the file to read from\n     * @return The number of bytes successfully read\n     * @throws IOException If there was an error reading the file\n     */\n    public int read(ByteBuffer bytes, long off) throws IOException {\n        if (_openMode != Mode.READ_ONLY) {\n            IOException ex = new IOException(\"File not opened for reading\");\n            _logger.throwing(\"dCacheFile\", \"read(byte[], long)\", ex);\n            throw ex;\n        }\n        ByteBuffer _commandBuffer = ByteBuffer.allocate(30);\n\n        if (off == 0) {\n            _commandBuffer.putInt(12);\n            _commandBuffer.putInt(2);\n        } else {\n            _commandBuffer.putInt(24);\n            _commandBuffer.putInt(11);\n            _commandBuffer.putLong(off);\n            _commandBuffer.putInt(0);\n        }\n\n        _commandBuffer.putLong(bytes.remaining());\n        _commandBuffer.flip();\n\n        _commandBuffer.rewind();\n        _clientChannel.write(_commandBuffer);\n\n        _logger.fine(\"Sending READ request for \" + bytes.remaining()\n                + \" bytes from \" + super.getName() + \".\");\n\n        _commandBuffer.clear();\n        _commandBuffer.limit(4);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        int num_bytes = 0;\n        while (num_bytes < 12)\n            num_bytes += _commandBuffer.getInt(); // Should be 12\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(num_bytes);\n\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        int ack = _commandBuffer.getInt();\n        int cmdCode = _commandBuffer.getInt(); // should be 2\n        int success = _commandBuffer.getInt();\n\n        if (success == 0) // Command was successful\n        {\n            _logger.fine(\"READ request successful [num_bytes = \" + num_bytes\n                    + \", ack = \" + ack + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success +\n            /* \", newConnection = \" + newConnection + */\"]\");\n        } else {\n            // TODO: bring this back\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n            _logger.fine(\"READ request successful [num_bytes = \" + num_bytes\n                    + \", ack = \" + ack + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success + \"]\\n\" + \"Server replied: \");\n\n            IOException ex = new IOException(detail);\n            _logger.throwing(\"dCacheFile\", \"read(byte[])\", ex);\n            throw ex;\n        }\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(8);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        num_bytes = _commandBuffer.getInt();\n        int data = _commandBuffer.getInt();\n\n        _logger.fine(\"READ: Data header received [num_bytes = \" + num_bytes\n                + \" data \" + data + \"]\");\n\n        int bytes_read = 0;\n        int position = 0;\n\n        while (true) {\n            _commandBuffer.rewind();\n            _commandBuffer.limit(4);\n            _clientChannel.read(_commandBuffer);\n\n            _commandBuffer.rewind();\n            num_bytes = _commandBuffer.getInt();\n            _logger.finest(\"READ: Number of bytes available from pool \"\n                    + num_bytes);\n\n            if (num_bytes < 0)\n                break;\n\n            int restPacket = num_bytes;\n\n            // We may need multiple read() calls to read 'num_bytes'\n            // from the pool data connection.\n\n            while (restPacket > 0) {\n                int block = restPacket;\n\n                for (int rest = block; rest > 0; ) {\n                    bytes.position(position);\n                    bytes.limit(position + rest);\n                    int rc = _clientChannel.read(bytes);\n                    if (rc < 0)\n                        throw new IOException(\n                                \"Read operation terminted prematurely\");\n\n                    rest -= rc;\n                    position += rc;\n                }\n                bytes_read += block;\n                restPacket -= block;\n            }\n        }\n\n        _commandBuffer.rewind();\n        _commandBuffer.limit(16);\n        _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.rewind();\n        num_bytes = _commandBuffer.getInt();\n        int fin = _commandBuffer.getInt();\n        cmdCode = _commandBuffer.getInt();\n        success = _commandBuffer.getInt();\n\n        if (success != 0) // Failed during READ operation\n        {\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n\n            _logger.severe(\"Failed while reading \" + super.getName() + \"[\"\n                    + \"num_bytes = \" + num_bytes + \", fin = \" + fin\n                    + \", cmdCode = \" + cmdCode + \", success = \" + success\n                    + \"]\\n\" + \"Server replied: \" + detail);\n            IOException ex = new IOException(detail);\n            _logger.throwing(\"dCacheFile\", \"read(byte[])\", ex);\n            throw ex;\n        }\n\n        _logger.fine(\"Read \" + bytes_read + \" bytes from \" + super.getName());\n        return (bytes_read == 0 ? -1 : bytes_read);\n    }\n\n    /**\n     * Not implemented\n     */\n    public int read(byte bytes[]) throws IOException {\n        // return read(bytes, 0);\n        throw new IOException(\"Not Implemented Yet\");\n    }\n\n    /**\n     * Get the pool ID of the file that the pool is coming from.\n     *\n     * @return The pool ID\n     */\n\n    public int getPoolID() {\n        if (!_connected) {\n            try {\n                open();\n                tell();\n                _connected = true;\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n        }\n\n        _logger.info(\"PoolID: \" + _poolID);\n        return _poolID;\n    }\n\n    /**\n     * Prepare the file for writing.\n     *\n     * @param position The position to start writing from\n     * @return The remaining number of bytes that can be written, if limited by the pool.\n     * @throws IOException If the writing fails\n     */\n\n    private long makeWritable(long position) throws IOException {\n        _commandBuffer.clear();\n\n        if (position == -1) {\n            _commandBuffer.putInt(4);\n            _commandBuffer.putInt(1);\n        } else {\n            _commandBuffer.putInt(16);\n            _commandBuffer.putInt(12);\n            _commandBuffer.putLong(position);\n            _commandBuffer.putInt(0);\n        }\n\n        _commandBuffer.flip();\n        _clientChannel.write(_commandBuffer);\n\n        _logger.fine(\"Sent WRITE request [\" + \"position = \" + position + \"]\");\n        _logger.fine(\"Receiving reply from pool\");\n\n        _commandBuffer.clear();\n        int bytes_read = 0;\n        while (bytes_read < 12)\n            bytes_read += _clientChannel.read(_commandBuffer);\n\n        _commandBuffer.flip();\n        int num_bytes = _commandBuffer.getInt();\n\n        int ack = _commandBuffer.getInt();\n        int cmdCode = _commandBuffer.getInt();\n        int success = _commandBuffer.getInt();\n\n        if (success != 0) {\n            // Command failed\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n            _logger.severe(\"WRITE failed for \" + super.getName() + \"[\"\n                    + \"num_bytes = \" + num_bytes + \", ack = \" + ack\n                    + \", cmdCode = \" + cmdCode + \", success = \" + success\n                    + \"]\\n\" + \"Server replied: \" + detail + \".\");\n            IOException ex = new IOException(detail);\n            _logger.throwing(\"dCacheFile\", \"write(byte[], int, int, long)\", ex);\n            throw ex;\n        }\n\n        if (num_bytes != 12) {\n            // Server sends extra parameters\n            if (num_bytes == 24) {\n                _commandBuffer.position(_commandBuffer.position() + 4);\n                _max_bytes = _commandBuffer.getLong();\n                _logger.fine(\"WRITE request succeeded for \" + super.getName()\n                        + \". Server limited write size. [\" + \"num_bytes = \"\n                        + num_bytes + \", ack = \" + ack + \", cmdCode = \"\n                        + cmdCode + \", success = \" + success + \", max_bytes = \"\n                        + _max_bytes + \"]\");\n            } else if (num_bytes == 16) {\n                _commandBuffer.position(_commandBuffer.position() + 4);\n\n                _logger.fine(\"WRITE request succeeded for \" + super.getName()\n                        + \". Server replied EXPECT_NEW_CONNECTION. [\"\n                        + \"num_bytes = \" + num_bytes + \", ack = \" + ack\n                        + \", cmdCode = \" + cmdCode + \", success = \" + success\n                        + \"]\");\n            }\n        } else {\n            _logger\n                    .fine(\"WRITE request succeeded for \" + super.getName()\n                            + \" [\" + \"num_bytes = \" + num_bytes + \", ack = \"\n                            + ack + \", cmdCode = \" + cmdCode + \", success = \"\n                            + success + \"]\");\n        }\n\n        _writable = true;\n        return _max_bytes;\n    }\n\n    /**\n     * Write to the file.\n     *\n     * @param buffer   Write <i>buffer</i> to the file\n     * @param position Start writing at <i>position</i> in the file\n     * @return The number of bytes written\n     * @throws IOException If the write operation failed\n     */\n    public int write(ByteBuffer buffer, long position)\n            throws IOException {\n        if (!_connected) {\n            open();\n            tell();\n            _connected = true;\n            _logger.fine(\"PoolID: \" + getPoolID());\n        }\n\n        try {\n            if (_commandBuffer == null)\n                _commandBuffer = ByteBuffer.allocate(128);\n            else\n                _commandBuffer.clear();\n\n            if (_openMode != Mode.WRITE_ONLY) {\n                IOException ex = new IOException(\"File not opened for writing\");\n                _logger.throwing(\"dCacheFile\", \"write(byte[], int, int, long)\",\n                        ex);\n                throw ex;\n            }\n\n            if (_max_bytes < buffer.remaining()) {\n                IOException ex = new IOException(\"Cannot write more than \"\n                        + _max_bytes + \" to \" + super.getName());\n                _logger.throwing(\"dCacheFile\", \"write(byte[], int, int, long)\",\n                        ex);\n                throw ex;\n            }\n\n            if (!_writable) {\n                makeWritable(position);\n\n\n            }\n\n            _commandBuffer.clear();\n            _commandBuffer.putInt(4);\n            _commandBuffer.putInt(8);\n\n            _commandBuffer.putInt(buffer.remaining());\n            _logger.finest(\"Writing \" + buffer.remaining() + \" bytes to \" + super.getName() + \" starting...\");\n\n            _commandBuffer.flip();\n\n            while (_commandBuffer.hasRemaining())\n                _clientChannel.write(_commandBuffer);\n\n            int bytes_written = 0;\n            while (buffer.hasRemaining()) {\n                bytes_written += _clientChannel.write(buffer);\n            }\n\n            _logger.finest(\"File was opened write only, telling pool transfer is complete\");\n\n            finishedWriting();\n\n            _logger.finest(\"[\" + super.getName() + \"] Bytes written = \" + bytes_written);\n            _max_bytes -= bytes_written;\n            return bytes_written;\n        } catch (IOException ex) {\n            ex.printStackTrace();\n            throw ex;\n        }\n    }\n\n    private void finishedWriting() throws IOException {\n        _commandBuffer.clear();\n\n        _commandBuffer.putInt(-1);\n        _commandBuffer.flip();\n        _clientChannel.write(_commandBuffer);\n        _commandBuffer.clear();\n\n        int num_bytes = 0;\n        while (num_bytes < 12)\n            num_bytes += _clientChannel.read(_commandBuffer);\n        _logger.finest(\"Bytes read: \" + num_bytes);\n        _commandBuffer.flip();\n        num_bytes = _commandBuffer.getInt();\n\n        int fin = _commandBuffer.getInt();\n        int cmdCode = _commandBuffer.getInt();\n        int success = _commandBuffer.getInt();\n\n        if (success != 0) // Some error occurred\n        {\n            byte utf[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(utf);\n            String detail = new String(utf);\n\n            IOException ex = new IOException(detail);\n            _logger.info(\"Error writing file to pool [\" + \"num_bytes = \"\n                    + num_bytes + \", fin = \" + fin + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success + \"]\\n\" + \"Server replied: \"\n                    + detail);\n            _logger.throwing(\"dCacheFile\", \"close\", ex);\n            throw ex;\n        } else {\n            _logger.fine(\"Success code received from the pool\");\n            _writable = false;\n        }\n    }\n\n    /**\n     * Close the file\n     *\n     * @throws IOException If there was an error closing the file\n     */\n    public void close() throws IOException {\n        ByteBuffer _commandBuffer = ByteBuffer.allocate(30);\n        _logger.info(\"Close on \" + super.getName());\n        _connected = false;\n\n        int num_bytes = 0, ack = 0, cmdCode = 0, success = -1;\n\n        try {\n            _commandBuffer.putInt(4);\n            _commandBuffer.putInt(4);\n            _commandBuffer.limit(8);\n            _commandBuffer.rewind();\n\n            _logger.fine(\"Sending close command to pool\");\n            _clientChannel.write(_commandBuffer);\n\n            _commandBuffer.clear();\n            _commandBuffer.limit(16);\n            int numread = 0;\n            while (numread < 16)\n                numread += _clientChannel.read(_commandBuffer);\n\n            if (numread >= 16) {\n                _commandBuffer.rewind();\n                num_bytes = _commandBuffer.getInt();\n                ack = _commandBuffer.getInt();\n                cmdCode = _commandBuffer.getInt();\n                success = _commandBuffer.getInt();\n            } else {\n                _logger.warning(\"Close command read \" + numread\n                        + \" bytes expected 16\");\n            }\n\n        } catch (BufferOverflowException of) {\n            _logger.fine(\"Closed() \" + of.getMessage());\n            if (_logger.isLoggable(Level.FINE))\n                _logger.throwing(\"dCacheFile\", \"close\", of);\n        } catch (BufferUnderflowException uf) {\n            _logger.fine(\"Closed() \" + uf.getMessage());\n            if (_logger.isLoggable(Level.FINE))\n                _logger.throwing(\"dCacheFile\", \"close\", uf);\n        }\n\n        if (success != 0) {\n            // Some error occurred\n            byte detail[] = new byte[_commandBuffer.remaining()];\n            _commandBuffer.get(detail);\n\n            IOException ex = new IOException(new String(detail));\n            _logger.info(\"Error writing file to pool [\" + \"num_bytes = \"\n                    + num_bytes + \", ack = \" + ack + \", cmdCode = \" + cmdCode\n                    + \", success = \" + success + \"]\\n\" + \"Server replied: \"\n                    + new String(detail));\n            _logger.throwing(\"dCacheFile\", \"close\", ex);\n            throw ex;\n        }\n\n        _poolCallback.unregisterCallback(_sessionID);\n        _controlConnection.unregisterCallback(_sessionID);\n\n        if (_logger.isLoggable(Level.FINE))\n            Thread.dumpStack();\n\n        _logger.info(super.getName() + \" closed\");\n    }\n\n\n//    public int write(byte b[]) throws IOException {\n//        return write(b, 0, 0, -1);\n//    }\n\n    /**\n     * Get length of the file\n     *\n     * @return The length of the file in bytes\n     */\n    public long length() {\n        return _filesize;\n    }\n\n    /**\n     * Not Implemented.\n     */\n\n    public int available() throws IOException {\n        return Integer.MAX_VALUE;\n    }\n\n    /**\n     * Get mode in which file was opened\n     *\n     * @return The file mode\n     */\n\n    public Mode mode() {\n        return _openMode;\n    }\n\n    protected void finalize() throws Throwable {\n        close();\n        super.finalize();\n    }\n\n    public void handleStreams(DataInputStream dataIn, DataOutputStream dataOut,\n                              String host, SocketChannel client) {\n        _clientChannel = client;\n        try {\n            _clientChannel.socket().setSendBufferSize(800000);\n        } catch (java.net.SocketException ex) {\n\n        }\n\n        _logger.info(\"Data connection callback for \" + super.getAbsolutePath());\n\n        if (host != null)\n            _poolID = host.hashCode();\n\n        _poolReplied = true;\n    }\n\n    public void handleDoorCommand(String input[]) {\n        _doorReply = input;\n        _doorReplied = true;\n    }\n\n    // / Represents the mode in which dCache files can be opened.\n    public enum Mode {\n        READ_ONLY, WRITE_ONLY\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/dCacheFileChannelProviderFactory.java",
    "content": "/*\n * Created on Jan 10, 2010\n */\npackage edu.caltech.hep.dcapj;\n\nimport edu.caltech.hep.dcapj.util.InvalidConfigurationException;\nimport lia.util.net.common.FDTCloseable;\nimport lia.util.net.common.FileChannelProvider;\nimport lia.util.net.common.FileChannelProviderFactory;\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.FDTWriterSession;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\n\n//import lia.util.net.copy.FDTCoordinatorSession;\n\n/**\n * Created to remove dependencies inside FDT core\n *\n * @author ramiro\n */\npublic class dCacheFileChannelProviderFactory implements FileChannelProviderFactory, FDTCloseable {\n\n    //keep them static; ignore the session\n    private final FileChannelProvider readerFileChannelProvider;\n    private final FileChannelProvider writerFileChannelProvider;\n    private final FileChannelProvider coordinatorChannelProvider;\n\n    public dCacheFileChannelProviderFactory() throws Exception {\n        dCapLayer.initialize();\n        this.readerFileChannelProvider = new dCacheReaderFileChannelProvider();\n        this.writerFileChannelProvider = new dCacheWriterFileChannelProvider();\n        this.coordinatorChannelProvider = new dCacheCoordinatorChannelProvider();\n    }\n\n    public FileChannelProvider newReaderFileChannelProvider(FDTReaderSession readerSession) {\n        return readerFileChannelProvider;\n    }\n\n    public FileChannelProvider newWriterFileChannelProvider(FDTWriterSession writerSession) {\n        return writerFileChannelProvider;\n    }\n\n//    @Override\n//    public FileChannelProvider newCoordinatorChannelProvider(FDTCoordinatorSession coordinatorSession) {\n//        return coordinatorChannelProvider;\n//    }\n\n    public boolean close(String downMessage, Throwable downCause) {\n        try {\n            dCapLayer.close();\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n        return true;\n    }\n\n    public boolean isClosed() {\n        return !dCapLayer.isInitialized();\n    }\n\n    private static final class dCacheReaderFileChannelProvider implements FileChannelProvider {\n\n        public File getFile(String fName) throws IOException {\n            try {\n                return new edu.caltech.hep.dcapj.dCacheFile(fName, edu.caltech.hep.dcapj.dCacheFile.Mode.READ_ONLY);\n            } catch (InvalidConfigurationException ice) {\n                throw new IOException(ice);\n            }\n        }\n\n        public int getPartitionID(File dCacheFile) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                return ((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getPoolID();\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n        public FileChannel getFileChannel(File dCacheFile, String openMode) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                try {\n                    return new edu.caltech.hep.dcapj.io.dCacheFileInputStream((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getChannel();\n                } catch (Exception ex) {\n                    throw new IOException(ex);\n                }\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n    }\n\n    private static final class dCacheWriterFileChannelProvider implements FileChannelProvider {\n\n        public File getFile(String fName) throws IOException {\n            try {\n                return new edu.caltech.hep.dcapj.dCacheFile(fName, edu.caltech.hep.dcapj.dCacheFile.Mode.WRITE_ONLY);\n            } catch (InvalidConfigurationException ice) {\n                throw new IOException(ice);\n            }\n        }\n\n        public int getPartitionID(File dCacheFile) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                return ((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getPoolID();\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n        public FileChannel getFileChannel(File dCacheFile, String openMode) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                try {\n                    return new edu.caltech.hep.dcapj.io.dCacheFileOutputStream((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getChannel();\n                } catch (Exception ex) {\n                    throw new IOException(ex);\n                }\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n    }\n\n    private static final class dCacheCoordinatorChannelProvider implements FileChannelProvider {\n\n        public File getFile(String fName) throws IOException {\n            try {\n                return new edu.caltech.hep.dcapj.dCacheFile(fName, edu.caltech.hep.dcapj.dCacheFile.Mode.WRITE_ONLY);\n            } catch (InvalidConfigurationException ice) {\n                throw new IOException(ice);\n            }\n        }\n\n        public int getPartitionID(File dCacheFile) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                return ((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getPoolID();\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n        public FileChannel getFileChannel(File dCacheFile, String openMode) throws IOException {\n            if (dCacheFile instanceof edu.caltech.hep.dcapj.dCacheFile) {\n                try {\n                    return new edu.caltech.hep.dcapj.io.dCacheFileOutputStream((edu.caltech.hep.dcapj.dCacheFile) dCacheFile).getChannel();\n                } catch (Exception ex) {\n                    throw new IOException(ex);\n                }\n            }\n            throw new IOException(\"File: \" + dCacheFile + \" is not an edu.caltech.hep.dcapj.dCacheFile object\");\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/dCapLayer.java",
    "content": "package edu.caltech.hep.dcapj;\n\nimport edu.caltech.hep.dcapj.util.ControlConnection;\nimport edu.caltech.hep.dcapj.util.IOCallback;\n\n/**\n * This class should be called by the application before starting any IO\n * operation using dcapJ protocol\n *\n * @author Faisal Khan\n */\n\npublic class dCapLayer {\n\n    /**\n     * guards _initialized flag\n     */\n    private static final Object initializedLock = new Object();\n\n    /**\n     * The IOCallback object that handles the mapping between session IDs and sessions.\n     */\n    static IOCallback _dataConnectionCallback = null;\n\n    /**\n     * The ControlConnection object.\n     */\n    static ControlConnection _controlConnection = null;\n\n    /**\n     * The Config object.\n     */\n    static Config _conf = null;\n\n    private static volatile boolean _isInitialized = false;\n\n\n    /**\n     * Initialize the library.\n     *\n     * @throws Exception If an error occurred\n     */\n    public static void initialize() throws Exception {\n        synchronized (initializedLock) {\n            if (!_isInitialized) {\n                _conf = new Config();\n                _dataConnectionCallback = new IOCallback();\n                _controlConnection = new ControlConnection();\n            }\n            _isInitialized = true;\n        }\n    }\n\n    public static final boolean isInitialized() {\n        synchronized (initializedLock) {\n            return _isInitialized;\n        }\n    }\n\n    /**\n     * Get the IOCallback object.\n     *\n     * @return The IOCallback object.\n     */\n    public static IOCallback getDataConnectionCallback() {\n        return _dataConnectionCallback;\n    }\n\n    /**\n     * Gets the ControlConnection object.\n     *\n     * @return The ControlConnection object.\n     */\n    public static ControlConnection getControlConnection() {\n        return _controlConnection;\n    }\n\n    /**\n     * Gets the Config object.\n     *\n     * @return The Config object.\n     */\n    public static Config getConfig() {\n        return _conf;\n    }\n\n    /**\n     * Close the library.\n     */\n    public static void close() {\n        _controlConnection.stop();\n        _dataConnectionCallback.shutdown();\n        _isInitialized = false;\n        System.out.println(\"dCapLayer closed!\");\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/io/dCacheFileInputStream.java",
    "content": "package edu.caltech.hep.dcapj.io;\n\nimport edu.caltech.hep.dcapj.dCacheFile;\nimport edu.caltech.hep.dcapj.nio.dCacheFileChannel;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\n\n/**\n * Use this class to read from a dCache file.\n *\n * @author Kamran Soomro\n */\npublic class dCacheFileInputStream extends FileInputStream {\n    private dCacheFile _file = null;\n\n    /**\n     * Create a dCacheFileInputStream object from the specified dCacheFile\n     * object.\n     *\n     * @param file The dCacheFile to use as the underlying file\n     * @throws java.lang.Exception If an error occurred\n     */\n    public dCacheFileInputStream(dCacheFile file) throws java.lang.Exception {\n        super(file);\n\n        _file = file;\n    }\n\n    /**\n     * Open a dCache file for reading.\n     *\n     * @param file The Pnfs path of the file to open\n     * @throws Exception If an occurred\n     */\n    public dCacheFileInputStream(String file) throws Exception {\n        this(new dCacheFile(file, dCacheFile.Mode.READ_ONLY));\n    }\n\n    /**\n     * Return an estimate of the number of bytes available.\n     *\n     * @return The estimated number of bytes available for reading\n     */\n    public int available() throws IOException {\n        return _file.available();\n    }\n\n    /**\n     * Reads up to <code>bytes.length</code> bytes of data from this input\n     * stream into an array of bytes. This method blocks until some input is\n     * available.\n     *\n     * @throws IOException If an error reading the file occurs\n     */\n    public int read(byte bytes[]) throws IOException {\n        return _file.read(bytes);\n    }\n\n    /**\n     * Reads up to <code>bytes.length</code> bytes of data from this input\n     * stream into an array of bytes. <code>len</code> is ignored.\n     */\n    public int read(byte bytes[], int off, int len) throws IOException {\n        // return _file.read(bytes, off);\n        return 0;\n    }\n\n    protected void finalize() throws IOException {\n        close();\n        super.finalize();\n    }\n\n    /**\n     * Get the {@link dCacheFileChannel} associated with this FileInputStream.\n     */\n    public FileChannel getChannel() {\n        return new dCacheFileChannel(_file, this);\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/io/dCacheFileOutputStream.java",
    "content": "package edu.caltech.hep.dcapj.io;\n\nimport edu.caltech.hep.dcapj.dCacheFile;\nimport edu.caltech.hep.dcapj.nio.dCacheFileChannel;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\n/**\n * Use this file to open a dCache file for writing.\n *\n * @author Kamran Soomro\n */\npublic class dCacheFileOutputStream extends FileOutputStream {\n    private dCacheFile _file = null;\n\n    /**\n     * Create a dCacheFileOutputStream object using the specified file as the\n     * underlying {@link dCacheFile}.\n     *\n     * @throws Exception If the file already exists or an error occurred\n     */\n    public dCacheFileOutputStream(dCacheFile file) throws Exception {\n        super(file);\n\n        _file = file;\n    }\n\n    /**\n     * Open the specified file for writing.\n     *\n     * @throws Exception If the file already exists or an error occurred\n     */\n    public dCacheFileOutputStream(String file) throws Exception {\n        this(new dCacheFile(file, dCacheFile.Mode.WRITE_ONLY));\n    }\n\n    /**\n     * Writes <code>bytes.length</code> bytes from the specified byte array to\n     * this file output stream.\n     *\n     * @throws IOException If an error occurred\n     */\n    public void write(byte bytes[]) throws IOException {\n        ByteBuffer buffer = ByteBuffer.wrap(bytes);\n        _file.write(buffer, -1);\n    }\n\n    /**\n     * Writes <code>len</code> bytes from the specified byte array starting at\n     * offset <code>off</code> to this file output stream.\n     *\n     * @throws IOException If an error occurred\n     */\n    public void write(byte bytes[], int off, int len) throws IOException {\n        ByteBuffer buffer = ByteBuffer.wrap(bytes, off, len);\n        _file.write(buffer, -1);\n    }\n\n    /**\n     * Close this output stream.\n     *\n     * @throws IOException If an error occurred\n     */\n    public void close() throws IOException {\n        _file.close();\n        super.close();\n    }\n\n    protected void finalize() throws IOException {\n        close();\n        super.finalize();\n    }\n\n    /**\n     * Get the {@link dCacheFileChannel} associated with thie output stream.\n     */\n    public FileChannel getChannel() {\n        return new dCacheFileChannel(_file, this);\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/nio/dCacheFileChannel.java",
    "content": "package edu.caltech.hep.dcapj.nio;\n\nimport edu.caltech.hep.dcapj.dCacheFile;\nimport edu.caltech.hep.dcapj.io.dCacheFileInputStream;\nimport edu.caltech.hep.dcapj.io.dCacheFileOutputStream;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.channels.WritableByteChannel;\n\n/**\n * This class implements the {@link java.nio.channels.FileChannel} API for a\n * {@link dCacheFile}. It is recommended to use this class to open a\n * {@link dCacheFile} instead of directly creating one.\n *\n * @author kamran\n * @see java.nio.channels.FileChannel\n */\npublic class dCacheFileChannel extends FileChannel {\n    private dCacheFile _file;\n\n    private dCacheFileInputStream _fileInStream;\n\n    private dCacheFileOutputStream _fileOutStream;\n\n    /**\n     * Create a new dCacheFileChannel object using a pre-exisiting\n     * {@link dCacheFile}.\n     *\n     * @param file The dCacheFile object that will be used to create this\n     *             dCacheFileChannel\n     */\n    public dCacheFileChannel(dCacheFile file, dCacheFileInputStream fileIn) {\n        _file = file;\n        _fileInStream = fileIn;\n    }\n\n    public dCacheFileChannel(dCacheFile file, dCacheFileOutputStream fileOut) {\n        _file = file;\n        _fileOutStream = fileOut;\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public void force(boolean metaData) throws IOException {\n        // TODO Auto-generated method stub\n        throw new IOException(\"Not implemented yet!\");\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public FileLock lock(long position, long size, boolean shared)\n            throws IOException {\n        // TODO Auto-generated method stub\n        return null;\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public MappedByteBuffer map(MapMode mode, long position, long size)\n            throws IOException {\n        // TODO Auto-generated method stub\n        return null;\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public long position() throws IOException {\n        return 0;\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public FileChannel position(long newPosition) throws IOException {\n        return null;\n    }\n\n    /**\n     * Read from the file.\n     *\n     * @param dst The ByteBuffer into which the read bytes will be stored. dCapJ\n     *            will try to fill the remaining number of bytes in dst. If EOF\n     *            is encountered, the limit will be set to the number of bytes\n     *            successfully read.\n     * @return The number of bytes successfully read. If EOF is encountered, -1\n     * will be returned.\n     * @throws IOException If read operation was not successful\n     */\n    public int read(ByteBuffer dst) throws IOException {\n        if (_file.mode() == dCacheFile.Mode.WRITE_ONLY)\n            throw new IOException(\"Not in read mode.\");\n\n        int result;\n        // byte buffer[] = new byte[dst.remaining()];\n\n        result = _file.read(dst, 0);\n\n        /*\n         * if (result > 0) { dst.put(buffer); dst.limit(result); }\n         */\n\n        return result;\n    }\n\n    /**\n     * Read from a specified position in the file without changing the location\n     * of the file's cursor.\n     *\n     * @param dst      The ByteBuffer into which the read bytes will be stored\n     * @param position The position in the file to read from\n     * @return The number of bytes successfully read. -1 of EOF is encountered\n     * and no bytes are read\n     * @throws IOException If the read operation was unsuccessful\n     */\n    public int read(ByteBuffer dst, long position) throws IOException {\n        if (_file.mode() == dCacheFile.Mode.WRITE_ONLY)\n            throw new IOException(\"Not in read mode.\");\n\n        long oldPosition = _file.tell();\n        _file.seek(position, false);\n        int result = read(dst);\n        _file.seek(oldPosition, false);\n\n        return result;\n    }\n\n    /**\n     * Fill the range given by [i]offset[/i] and [i]length[/i] with bytes from\n     * the file.\n     *\n     * @param dsts   The array into which the bytes will be stored\n     * @param offset The offset of the ByteBuffer from which to start filling\n     * @param length The total number of ByteBuffers to fill\n     * @throws IOException If the read operation was unsuccessful\n     */\n    public long read(ByteBuffer[] dsts, int offset, int length)\n            throws IOException {\n        long result = 0;\n\n        for (int i = offset; i < offset + length; i++) {\n            result += read(dsts[i]);\n        }\n\n        return result;\n    }\n\n    /**\n     * Get the file size.\n     *\n     * @return The size of the file in bytes\n     * @throws IOException If the operation was unsuccessful\n     */\n    public long size() throws IOException {\n        if (_file.mode() == dCacheFile.Mode.WRITE_ONLY)\n            throw new IOException(\n                    \"size() operation not available in write mode\");\n\n        return _file.length();\n    }\n\n    /**\n     * Write to the file file from the ReadableByteChannel.\n     *\n     * @param src      The channel to read from\n     * @param position The position within the file to write to\n     * @param count    The number of bytes to read\n     * @throws IOException If the operation was unsuccessful\n     */\n    public long transferFrom(ReadableByteChannel src, long position, long count)\n            throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate((int) count);\n        src.read(buffer);\n        buffer.flip();\n        return write(buffer, position);\n    }\n\n    /**\n     * Read from the file into the WritableByteChannel.\n     *\n     * @param position The position in the file to read from\n     * @param count    The number of bytes to be read from the file\n     * @param target   The WritableByteChannel to write to\n     * @throws IOException If the operation was unsuccessful\n     */\n    @Override\n    public long transferTo(long position, long count, WritableByteChannel target)\n            throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate((int) count);\n        read(buffer, position);\n        buffer.flip();\n        return target.write(buffer);\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public FileChannel truncate(long size) throws IOException {\n        // TODO Auto-generated method stub\n        return null;\n    }\n\n    /**\n     * Not implemented.\n     */\n    @Override\n    public FileLock tryLock(long position, long size, boolean shared)\n            throws IOException {\n        // TODO Auto-generated method stub\n        return null;\n    }\n\n    /**\n     * Write to the file.\n     *\n     * @param src The ByteBuffer to write to the file\n     * @return The number of bytes successfully written\n     * @throws IOException If the operation fails\n     */\n    @Override\n    public int write(ByteBuffer src) throws IOException {\n        if (_file.mode() == dCacheFile.Mode.READ_ONLY)\n            throw new IOException(\"Not in write mode\");\n\n        return _file.write(src, -1);\n    }\n\n    /**\n     * Write to the file.\n     * <p>\n     * <i>position</i> is ignored. The writing is performed sequentially.\n     *\n     * @param src      The ByteBuffer to write\n     * @param position Ignored\n     * @return The number of bytes successfully written\n     * @throws IOException If the operation fails\n     * @see #write(ByteBuffer)\n     */\n    @Override\n    public int write(ByteBuffer src, long position) throws IOException {\n        if (_file.mode() == dCacheFile.Mode.READ_ONLY)\n            throw new IOException(\"Not in write mode\");\n\n        return _file.write(src, position);\n    }\n\n    /**\n     * Write from the array to the file.\n     *\n     * @param srcs   The ByteBuffer array to write from\n     * @param offset The offset of the ByteBuffer in src to start writing from\n     * @param length The number ByteBuffers to write to the file\n     * @return The number of bytes successfully written to the file\n     * @throws IOException If the operation fails\n     */\n    @Override\n    public long write(ByteBuffer[] srcs, int offset, int length)\n            throws IOException {\n        long result = 0;\n\n        if (_file.mode() == dCacheFile.Mode.READ_ONLY)\n            throw new IOException(\"Not in write mode\");\n\n        for (int i = offset; i < offset + length; i++) {\n            result += write(srcs[i]);\n        }\n\n        return result;\n    }\n\n    /**\n     * Close this channel and the underlying {@link dCacheFile}.\n     *\n     * @throws IOException If there was an error trying to close the file\n     */\n    protected void implCloseChannel() throws IOException {\n        _file.close();\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/test/Main.java",
    "content": "package edu.caltech.hep.dcapj.test;\n\nimport edu.caltech.hep.dcapj.dCapLayer;\nimport edu.caltech.hep.dcapj.io.dCacheFileOutputStream;\nimport edu.caltech.hep.dcapj.nio.dCacheFileChannel;\n\nimport java.nio.ByteBuffer;\n\npublic class Main {\n\n    public static void main(String args[]) throws Exception {\n        dCapLayer.initialize(); // Must be called to initialize the library\n        // dCacheFileChannel fcOu = (dCacheFileChannel)new\n        // dCacheFileInputStream(\"/media/itouch/data/fileIn\").getChannel();\n        dCacheFileChannel fcOut = (dCacheFileChannel) new dCacheFileOutputStream(\n                \"/pnfs/192.168.0.254/data/fileOut\").getChannel();\n        ByteBuffer buffer = ByteBuffer.allocate(1024);\n\n        buffer.put(\"Hello\\n\".getBytes());\n\n        buffer.flip();\n        fcOut.write(buffer, 5);\n        buffer.flip();\n        fcOut.write(buffer, 0);\n\n        fcOut.close();\n        dCapLayer.close();\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/test/Main2.java",
    "content": "package edu.caltech.hep.dcapj.test;\n\nimport edu.caltech.hep.dcapj.dCapLayer;\nimport edu.caltech.hep.dcapj.io.dCacheFileInputStream;\n\nimport java.io.FileOutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\npublic class Main2 {\n\n    public static void main(String args[]) {\n        // initialize the dcap layer\n        try {\n            dCapLayer.initialize();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        dCacheFileInputStream din = null;\n        FileOutputStream fos = null;\n        try {\n\n            din = new dCacheFileInputStream(\"/pnfs/192.168.0.254/data/test\");\n            fos = new FileOutputStream(\"/tmp/out\");\n\n            FileChannel fiW = fos.getChannel();\n            FileChannel fiC = din.getChannel();\n            int default_buffer_size = 500 * 1024;\n\n            long fileSize = fiC.size();\n\n            System.out.println(\"*** Total file size  = \" + fiC.size());\n            System.out.println(\"*** Default buffer size  = \"\n                    + default_buffer_size);\n\n            ByteBuffer buffer = ByteBuffer.allocate(default_buffer_size);\n            System.out.println(\"*** Buffer allocated\");\n\n            long read = fileSize;\n            while (true) {\n                long nr = fiC.read(buffer);\n                System.out.println(\"[Main] fic.read() returned \" + nr);\n\n                if (nr <= 0)\n                    break;\n\n                System.out.println(\"*** Read bytes = \" + nr);\n\n                read -= nr;\n                buffer.limit((int) nr).flip();\n                fiW.write(buffer);\n                buffer.clear();\n            }\n\n            dCapLayer.close();\n\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                din.close();\n                fos.close();\n            } catch (Exception e) {\n            }\n            System.out.println(\"Closed!\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/test/Main3.java",
    "content": "package edu.caltech.hep.dcapj.test;\n\nimport edu.caltech.hep.dcapj.PnfsUtil;\nimport edu.caltech.hep.dcapj.dCapLayer;\nimport edu.caltech.hep.dcapj.io.dCacheFileInputStream;\nimport edu.caltech.hep.dcapj.io.dCacheFileOutputStream;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\n/**\n * Copy from dcache to filesystem or from filesystem to dache.. no other option\n * available!\n */\n\npublic class Main3 implements Runnable {\n\n    private String source = null;\n\n    private String destination = null;\n\n    private FileInputStream fileIn = null;\n    private FileOutputStream fileOut = null;\n    private dCacheFileInputStream dFileIn = null;\n    private dCacheFileOutputStream dFileOut = null;\n\n    public Main3(String src, String dest) {\n        this.source = src;\n        this.destination = dest;\n    }\n\n    public static void main(String args[]) {\n\n        // initialize the dcap layer\n        try {\n            dCapLayer.initialize();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        int ioPairs = args.length / 2; // based on soruce, dest pair\n\n        if (ioPairs == 0 || (ioPairs != 1 && ioPairs % 2 != 0)) {\n            System.out.println(\"Not enough source/dest pair! \" + ioPairs);\n            dCapLayer.close();\n            return;\n        }\n\n        Main3 main3[] = new Main3[ioPairs];\n        Thread ioThreads[] = new Thread[ioPairs];\n        int count = 0;\n\n        for (int i = 0; i < ioPairs; i++) {\n            main3[i] = new Main3(args[count++], args[count++]);\n            ioThreads[i] = new Thread(main3[i]);\n            ioThreads[i].start();\n        }\n\n        try {\n\n            for (int i = 0; i < ioPairs; i++)\n                ioThreads[i].join();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        dCapLayer.close();\n    }\n\n    public void run() {\n        doIO();\n    }\n\n    public void doIO() {\n\n        FileChannel fC1 = null;\n        FileChannel fC2 = null;\n\n        try {\n\n            FileChannel[] temp = getFileChannels();\n            fC1 = temp[0];\n            fC2 = temp[1];\n\n            if (fC1 == null) {\n                System.out.println(\"Failed to get IO channel for file \"\n                        + this.source);\n                return;\n            }\n\n            if (fC2 == null) {\n                System.out.println(\"Failed to get IO channel for file \"\n                        + this.destination);\n                return;\n            }\n\n            int default_buffer_size = 5 * 1024;\n\n            ByteBuffer buffer = ByteBuffer.allocate(default_buffer_size);\n\n            long bytesRem = fC1.size();\n\n            while (true) {\n                int buffSize = Math.min(default_buffer_size, (int) bytesRem);\n                buffer.limit(buffSize);\n\n                long nr = fC1.read(buffer);\n\n                if (nr <= 0)\n                    break;\n\n                bytesRem -= nr;\n                buffer.limit((int) nr).flip();\n                fC2.write(buffer);\n                buffer.clear();\n            }\n\n            System.out.println(\"Done \" + this.source + \" -> \"\n                    + this.destination);\n        } catch (Exception e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                fC1.close();\n                fC2.close();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private FileChannel[] getFileChannels() throws Exception {\n        FileChannel fc[] = new FileChannel[2];\n\n        if (!PnfsUtil.isPnfs(this.source)) {\n            dFileOut = new dCacheFileOutputStream(this.destination);\n            fc[1] = dFileOut.getChannel();\n\n            fileIn = new FileInputStream(this.source);\n            fc[0] = fileIn.getChannel();\n        } else {\n            dFileIn = new dCacheFileInputStream(this.source);\n            fc[0] = dFileIn.getChannel();\n\n            fileOut = new FileOutputStream(this.destination);\n            fc[1] = fileOut.getChannel();\n        }\n\n        return fc;\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/ControlCommandCallback.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\npublic interface ControlCommandCallback {\n    public void handleDoorCommand(String command[]);\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/ControlConnection.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\nimport edu.caltech.hep.dcapj.Config;\nimport edu.caltech.hep.dcapj.PnfsUtil;\nimport edu.caltech.hep.dcapj.dCapLayer;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.util.Hashtable;\nimport java.util.logging.Logger;\n\npublic class ControlConnection implements Runnable {\n\n    private static final Logger _logger = Logger\n            .getLogger(ControlConnection.class.getName());\n    protected Hashtable<Integer, ControlCommandCallback> callbacks;\n    private Socket _client = null;\n\n    private PrintWriter _clientOut = null;\n\n    private BufferedReader _clientIn = null;\n\n    private boolean _shouldBeRunning = true;\n\n    private boolean _stopped = true;\n\n    private Thread _clientThread = null;\n\n    private Integer _nextSessionID = -1;\n\n    public ControlConnection() throws IOException,\n            InvalidConfigurationException {\n        initialize();\n    }\n\n    private void initialize() throws IOException, InvalidConfigurationException {\n        Config conf = dCapLayer.getConfig();\n\n        if (conf == null) {\n            String emsg = \"Configuration object was null\";\n            throw new InvalidConfigurationException(emsg);\n        }\n        String dCapHost = conf.getdCapDoor(); // host:port\n\n        if (dCapHost == null) {\n            _logger\n                    .fine(\"No defautl dCap host defined. dCapJ will try to find \"\n                            + \" it through pnfs layer\");\n\n            // if no dcap door address specified in conf file, try to figure out\n            // through the pnfs layer. If the pnfs was also not specified,\n            // assume it to be /pnfs/fs/usr/data\n            try {\n                dCapHost = PnfsUtil\n                        .getdCapDoor((conf.getPnfsDir() == null ? \"/pnfs/fs/usr/data\"\n                                : conf.getPnfsDir()));\n            } catch (Exception e) {\n                _logger.finest(e.getMessage());\n            }\n        }\n\n        String ip = null;\n        int port = -1;\n\n        // dcapHost can still be null\n        if (dCapHost != null) {\n            String tmp[] = dCapHost.split(\":\");\n            if (tmp.length > 1) {\n                ip = tmp[0];\n                try {\n                    System.out.println(tmp[1]);\n                    port = Integer.parseInt(tmp[1]);\n                } catch (NumberFormatException nfe) {\n                    _logger.severe(\"Illegal port number in dCap host address\");\n                }\n            }\n        }\n\n        if (ip == null || port == -1) {\n            // we failed to find a valid door ip and port. Let's throw\n            InvalidConfigurationException invc = new InvalidConfigurationException(\n                    \"dCap door host and port are not properly defined.\");\n            _logger.throwing(\"ControlConnection\", \"initialize\", invc);\n            throw invc;\n        }\n\n        _logger.fine(\"Connection to dCap door at \" + ip + \":\" + \"port\");\n        _client = new Socket(ip, port);\n\n        _clientOut = new PrintWriter(_client.getOutputStream());\n        _clientIn = new BufferedReader(new InputStreamReader(_client\n                .getInputStream()));\n        _logger.finer(\"IO streams initialized for dCap door\");\n\n        doHelloConversation();\n\n        callbacks = new Hashtable<Integer, ControlCommandCallback>();\n\n        //\n        start();\n    }\n\n    private void doHelloConversation() throws IOException {\n\n        sendCommand(\"0 0 client hello 0 0 1 1\");\n\n        String reply = _clientIn.readLine();\n        String doorReply[] = null;\n\n        if (reply != null)\n            doorReply = reply.split(\" \");\n\n        if (doorReply == null || doorReply.length < 4) {\n            throw new IOException(\n                    \"Not a valid reply from dcap door; where reply = \"\n                            + doorReply);\n        }\n\n        if (doorReply[3].equals(\"welcome\")) {\n            _logger.fine(\"dCap door replied: \" + doorReply[3]);\n        } else if (doorReply[3].equals(\"failed\")) {\n            _logger.severe(\"dCap door rejected connection!\");\n            sendCommand(\"0 0 client byebye\");\n            throw new IOException(\"Error Code: \"\n                    + (doorReply.length > 5 ? doorReply[4] : \"Unknown\")\n                    + \" Error Message: \"\n                    + (doorReply.length > 6 ? doorReply[5] : \" Unknown\"));\n        } else if (doorReply[3].equals(\"byebye\")) {\n            _logger.severe(\"dCap door closed connection.\");\n            throw new IOException(\"Failed to initialize dCap door\");\n        }\n\n    }\n\n    public void run() {\n\n        String reply = null;\n\n        while (_shouldBeRunning) {\n            try {\n                Thread.sleep(500);\n\n                if (_clientIn.ready())\n                    reply = _clientIn.readLine();\n                else\n                    continue;\n\n            } catch (IOException e) {\n                // TODO:recover connection if it is down\n                e.printStackTrace();\n            } catch (InterruptedException ie) {\n                ie.printStackTrace();\n            }\n\n            if (reply == null) {\n                _logger.warning(\"Received null in command loop \");\n                // TODO: perhaps a pingpong to test the control connection.\n                //\n                break;\n            }\n\n            _logger.finer(\"Received command reply: \\\"\" + reply + \"\\\"\");\n            String replyParts[] = reply.split(\" \");\n            if (replyParts.length > 0) {\n                int session = -1;\n                try {\n                    session = Integer.parseInt(replyParts[0]);\n                } catch (NumberFormatException nfe) {\n                    _logger\n                            .warning(\"Failed to parse door reply to get session ID \"\n                                    + replyParts[0]);\n                }\n\n                ControlCommandCallback ccc = callbacks.get(session);\n                if (ccc != null) {\n                    ccc.handleDoorCommand(replyParts);\n                    _logger.fine(\"Notified session \" + session\n                            + \" for command callback\");\n                } else {\n                    _logger.warning(\"No callback registered/found for session \"\n                            + session);\n                }\n            }\n        }\n        try {\n            _clientIn.close();\n            _clientOut.close();\n            _client.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        _stopped = true;\n    }\n\n    protected void start() {\n        if (_clientThread == null) {\n            _shouldBeRunning = true;\n            _clientThread = new Thread(this);\n            _clientThread.setName(\"Server\");\n            _clientThread.start();\n        }\n    }\n\n    public void stop() {\n        _shouldBeRunning = false;\n        _logger.fine(\"Closting control connection\");\n\n        try {\n            _clientThread.join();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public boolean isStopped() {\n        return _stopped;\n    }\n\n    /**\n     * Register a command callback against a give sessionID to multplex\n     * in-comming control commands\n     */\n    public boolean registerCallback(int sessionID, ControlCommandCallback ccc) {\n        if (!callbacks.contains(sessionID)) {\n            callbacks.put(sessionID, ccc);\n            _logger.fine(\"Registered command call back receiver for sessionID \"\n                    + sessionID);\n            return true;\n        }\n\n        return false;\n    }\n\n    public boolean unregisterCallback(int sessionID) {\n        if (callbacks.contains(sessionID)) {\n            _logger.info(\"Removing callback receiver for sessionID \"\n                    + sessionID);\n            callbacks.remove(sessionID);\n            return true;\n        }\n        return false;\n    }\n\n    public void sendCommand(String command) throws IOException {\n        _clientOut.println(command);\n        _clientOut.flush();\n        _logger.finer(\"Sent command: \\\"\" + command + \"\\\"\");\n    }\n\n    public int getNextSessionID() {\n        int temp = -1;\n        synchronized (_nextSessionID) {\n            temp = ++_nextSessionID;\n        }\n        return temp;\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/DataConnectionCallback.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.nio.channels.SocketChannel;\n\npublic interface DataConnectionCallback {\n    public void handleStreams(DataInputStream dataIn, DataOutputStream dataOut,\n                              String host, SocketChannel client);\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/IOCallback.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.Hashtable;\nimport java.util.logging.Logger;\n\npublic class IOCallback extends ServerNIO {\n\n    private static final Logger logger = Logger.getLogger(IOCallback.class\n            .getName());\n    protected Hashtable<Integer, DataConnectionCallback> callbacks;\n\n    public IOCallback() throws IOException {\n        callbacks = new Hashtable<Integer, DataConnectionCallback>();\n        start();\n        logger.info(\"Data connecation callback is now active\");\n    }\n\n    public void handleConnection(SocketChannel client) {\n        DataInputStream poolIn = null;\n        DataOutputStream poolOut = null;\n        if (client == null) {\n            logger.severe(\"IO callback channel failed for unknown file\");\n            return;\n        }\n\n        try {\n            logger.fine(\"Handling connection from \"\n                    + client.socket().getInetAddress().getHostAddress() + \":\"\n                    + client.socket().getPort());\n            poolIn = new DataInputStream(client.socket().getInputStream());\n            poolOut = new DataOutputStream(client.socket().getOutputStream());\n\n            ByteBuffer buffer = ByteBuffer.allocate(4);\n            client.read(buffer);\n\n            buffer.flip();\n            int sessionID = buffer.getInt();\n\n            logger.info(\"Received callback for session id \" + sessionID);\n\n            // handover the connection to appropriate dCache-file block\n            DataConnectionCallback connection = callbacks.get(sessionID);\n\n            if (connection != null) {\n                logger.fine(\"Information callback reciever for sessionID \"\n                        + sessionID);\n                connection.handleStreams(poolIn, poolOut, client.socket()\n                        .getInetAddress().getHostAddress(), client);\n            } else {\n                logger.warning(\"No callback receiver registred for sessionID \"\n                        + sessionID);\n            }\n\n        } catch (IOException ioe) {\n            ioe.printStackTrace();\n        } finally {\n        }\n    }\n\n    /**\n     * Register a connection callback against a given sessionID to multplex\n     * in-comming pool connection\n     */\n    public boolean registerCallback(int sessionID,\n                                    DataConnectionCallback connection) {\n        if (!callbacks.contains(sessionID)) {\n            callbacks.put(sessionID, connection);\n            logger.fine(\"Registered data call back receiver for sessionID \"\n                    + sessionID);\n            return true;\n        }\n\n        return false;\n    }\n\n    public boolean unregisterCallback(int sessionID) {\n        if (callbacks.contains(sessionID)) {\n            logger.info(\"Removing callback receiver for sessionID \"\n                    + sessionID);\n            callbacks.remove(sessionID);\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/InvalidConfigurationException.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\npublic class InvalidConfigurationException extends Exception {\n\n    public InvalidConfigurationException() {\n        super();\n    }\n\n    public InvalidConfigurationException(String message) {\n        super(message);\n    }\n\n    public InvalidConfigurationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public InvalidConfigurationException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/Server.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic abstract class Server implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(Server.class\n            .getName());\n\n    protected boolean accept;\n\n    protected ServerSocket _server = null;\n    protected int timeout = 5 * 60 * 1000;\n    private Thread serverThread = null;\n    private boolean secure = true;\n\n    public Server() throws IOException {\n        this(0);\n    }\n\n    public Server(final int port) throws IOException {\n        init(port);\n    }\n\n    protected void init(final int port) throws IOException {\n        _server = new ServerSocket(port);\n        System.out.println(\"Server initialized\");\n        logger.log(Level.INFO, \"Server initialzed to listen on port \"\n                + _server.getLocalPort());\n    }\n\n    public int getTimeout() {\n        return this.timeout;\n    }\n\n    public void setTimeout(final int timeout) {\n        this.timeout = timeout;\n    }\n\n    public void shutdown() {\n        accept = false;\n        try {\n            _server.close();\n        } catch (final Exception e) {\n        }\n\n        /*\n         * final SocketFactory factory = SocketFactory.getDefault(); Socket s =\n         * null; try { s = factory.createSocket(InetAddress.getLocalHost(),\n         * getPort()); s.getInputStream(); } catch (final Exception e) {\n         *  } finally { if (s != null) { try { s.close(); } catch (final\n         * Exception e) { } } }\n         */\n        try {\n            serverThread.join();\n        } catch (InterruptedException ie) {\n            ie.printStackTrace();\n        }\n\n        serverThread = null;\n        _server = null;\n    }\n\n    protected void start() {\n        if (serverThread == null) {\n            accept = true;\n            serverThread = new Thread(this);\n            serverThread.setName(\"Server\");\n            serverThread.start();\n        }\n    }\n\n    public int getPort() {\n        return _server.getLocalPort();\n    }\n\n    // public String getHostAddress() {\n    // return hostAddress;\n\n    // }\n\n    public void run() {\n        Socket socket = null;\n\n        while (accept) {\n\n            try {\n                socket = _server.accept();\n                if (!accept) {\n                    break;\n                }\n                socket.setSoTimeout(getTimeout());\n            } catch (final IOException e) {\n                if (accept) {\n                    logger.log(Level.WARNING, \"Server died: \" + e.getMessage(),\n                            e);\n                }\n                break;\n            }\n            handleConnection(socket);\n        }\n    }\n\n    protected abstract void handleConnection(Socket client);\n\n}\n"
  },
  {
    "path": "src/edu/caltech/hep/dcapj/util/ServerNIO.java",
    "content": "package edu.caltech.hep.dcapj.util;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic abstract class ServerNIO implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(ServerNIO.class\n            .getName());\n\n    protected boolean accept;\n\n    protected ServerSocketChannel _serverChannel = null;\n\n    protected ServerSocket _server = null;\n    protected int timeout = 5 * 60 * 1000;\n    private Thread serverThread = null;\n    private boolean secure = true;\n\n    public ServerNIO() throws IOException {\n        this(0);\n    }\n\n    public ServerNIO(final int port) throws IOException {\n        init(port);\n    }\n\n    protected void init(final int port) throws IOException {\n        _serverChannel = ServerSocketChannel.open();\n        // _serverChannel.configureBlocking(false);\n\n        _server = _serverChannel.socket();\n        InetSocketAddress address = new InetSocketAddress(port);\n        _server.bind(address);\n\n        logger.log(Level.INFO, \"ServerNIO initialzed to listen on port \"\n                + _server.getLocalPort());\n    }\n\n    public int getTimeout() {\n        return this.timeout;\n    }\n\n    public void setTimeout(final int timeout) {\n        this.timeout = timeout;\n    }\n\n    public void shutdown() {\n        accept = false;\n        try {\n            _server.close();\n        } catch (final Exception e) {\n        }\n\n        /*\n         * final SocketFactory factory = SocketFactory.getDefault(); Socket s =\n         * null; try { s = factory.createSocket(InetAddress.getLocalHost(),\n         * getPort()); s.getInputStream(); } catch (final Exception e) {\n         *  } finally { if (s != null) { try { s.close(); } catch (final\n         * Exception e) { } } }\n         */\n        try {\n            serverThread.join();\n        } catch (InterruptedException ie) {\n            ie.printStackTrace();\n        }\n\n        serverThread = null;\n        _server = null;\n    }\n\n    protected void start() {\n        if (serverThread == null) {\n            accept = true;\n            serverThread = new Thread(this);\n            serverThread.setName(\"dCapIOCallbackServerNIO\");\n            serverThread.start();\n        }\n    }\n\n    public int getPort() {\n        return _server.getLocalPort();\n    }\n\n    // public String getHostAddress() {\n    // return hostAddress;\n\n    // }\n\n    public void run() {\n        SocketChannel socketChannel = null;\n\n        while (accept) {\n\n            try {\n                socketChannel = _serverChannel.accept();\n                if (!accept) {\n                    break;\n                }\n                // socket.setSoTimeout(getTimeout());\n            } catch (final IOException e) {\n                if (accept) {\n                    logger.log(Level.WARNING, \"ServerNIO died: \"\n                            + e.getMessage(), e);\n                }\n                break;\n            }\n            handleConnection(socketChannel);\n        }\n    }\n\n    protected abstract void handleConnection(SocketChannel client);\n\n}\n"
  },
  {
    "path": "src/lia/gsi/ClientTest.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi;\n\nimport lia.gsi.net.GSIGssSocketFactory;\n\nimport java.io.*;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.UnknownHostException;\n\n/**\n * @author Adrian Muraru\n */\npublic class ClientTest {\n\n    public static void main(String[] args) throws UnknownHostException, IOException {\n        GSIGssSocketFactory factory = new GSIGssSocketFactory();\n        Socket socket = factory.createSocket(InetAddress.getByName(args[0]), 54320, false, false);\n        OutputStream outputStream = socket.getOutputStream();\n        InputStream inputStream = socket.getInputStream();\n\n        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));\n        System.out.println(\"Received:\" + br.readLine());\n        PrintWriter pw = new PrintWriter(outputStream, true);\n        pw.println(\"Hello\");\n    }\n}\n"
  },
  {
    "path": "src/lia/gsi/FDTGSIServer.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi;\n\nimport lia.util.net.copy.FDTSessionManager;\nimport lia.util.net.copy.transport.ControlChannel;\nimport org.ietf.jgss.GSSCredential;\n\nimport javax.security.auth.Subject;\nimport java.net.Socket;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n\n/**\n * This class will handle all the FDT GSI requests\n * It overrides handleConversation from the base class.\n *\n * @author ramiro\n */\npublic class FDTGSIServer extends GSIServer {\n\n    private static final FDTSessionManager fdtSessionManager = FDTSessionManager.getInstance();\n    private static final Logger logger = Logger.getLogger(FDTGSIServer.class.getName());\n\n    public FDTGSIServer() throws Exception {\n        super();\n    }\n\n    public FDTGSIServer(int port) throws Exception {\n        this((String) null, (String) null, port);\n    }\n\n    public FDTGSIServer(GSSCredential cred, int port) throws Exception {\n        super(cred, port);\n    }\n\n    public FDTGSIServer(String serverKey, String serverCert, int port) throws Exception {\n        super(generateGSSCredential(serverKey, serverCert), port);\n    }\n\n    public void start() {\n        super.start();\n    }\n\n    protected void handleConversation(GSIServer parent, Socket client, Subject peerSubject) {\n        ControlChannel ct = null;\n\n        try {\n            ct = new ControlChannel(parent, client, peerSubject, fdtSessionManager);\n            fdtSessionManager.addFDTClientSession(ct);\n        } catch (Throwable t) {\n            ct = null;\n            throw new IllegalStateException(\"[ FDTGSIServer ] Cannot instantiate ControlChannel for client: \" + client, t);\n        }\n\n        if (ct != null) {\n            new Thread(ct, \"ControlChannel thread for [ \" + client.getInetAddress() + \":\" + client.getPort() + \" ]\").start();\n        }\n\n        logger.log(Level.INFO, \"[ FDTGSIServer ] ControlChannel for client: \" + client + \" started!\");\n    }\n}\n"
  },
  {
    "path": "src/lia/gsi/GSIServer.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi;\n\nimport lia.gsi.net.GSIBaseServer;\nimport lia.gsi.net.Peer;\nimport org.globus.gsi.CredentialException;\nimport org.globus.gsi.GSIConstants;\nimport org.globus.gsi.GlobusCredentialException;\nimport org.globus.gsi.X509Credential;\nimport org.globus.gsi.gssapi.GlobusGSSCredentialImpl;\nimport org.globus.gsi.gssapi.jaas.UserNamePrincipal;\nimport org.ietf.jgss.GSSCredential;\nimport org.ietf.jgss.GSSException;\n\nimport javax.security.auth.Subject;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Generic GSI Server\n *\n * @author Adrian Muraru\n */\npublic class GSIServer extends GSIBaseServer {\n\n    protected static final int PORT = 54320;\n    private static Logger logger = Logger.getLogger(GSIServer.class.getName());// LogFactory.getLog(GSIServer.class.getName());\n\n    /**\n     * initializes the GSIServer with the default credentials and starting listening on default port\n     *\n     * @throws IOException\n     */\n    public GSIServer(int port) throws Exception {\n        this((String) null, (String) null, port);\n    }\n\n    /**\n     * initializes the GSIServer with the default credentials and starting listening on the default port\n     *\n     * @throws IOException\n     */\n    public GSIServer() throws Exception {\n        this((String) null, (String) null, PORT);\n    }\n\n    /**\n     * initializes the GSIServer with the provided credentials and starts to listen to client connections on the port passed as a parameter\n     *\n     * @param cred the credentials used by this server, if null then default credentials are used.\n     * @param port the port number used by this server\n     */\n    public GSIServer(GSSCredential cred, int port) throws Exception {\n        super(cred, port);\n    }\n\n    /**\n     * initializes the GSIServer with the provided credentials and starts to listen to client connections on the port passed as a parameter\n     *\n     * @param serverKey\n     * @param serverCert\n     * @param port\n     * @throws Exception\n     */\n    public GSIServer(String serverKey, String serverCert, int port) throws Exception {\n        super(generateGSSCredential(serverKey, serverCert), port);\n    }\n\n    public static GSSCredential generateGSSCredential(String serverKey, String serverCert) throws GlobusCredentialException, CredentialException, IOException, GSSException {\n        X509Credential credentials;\n\n        // first try to read the service cert and key from the jvm properties\n        if (serverKey == null && serverCert == null) {\n            // read it from jvm properties\n            serverKey = System.getProperty(\"X509_SERVICE_KEY\");\n            serverCert = System.getProperty(\"X509_SERVICE_CERT\");\n        }\n\n        // if not, try to read the service cert and key from the environment\n        if (serverKey == null && serverCert == null) {\n            // read it from env\n            serverKey = System.getenv(\"X509_HOST_KEY\");\n            serverCert = System.getenv(\"X509_HOST_CERT\");\n        }\n\n        // if not, try to read the default location /etc/grid-security/host{cert,key}.pem\n        if (serverKey == null && serverCert == null) {\n            // read it from env\n            serverKey = \"/etc/grid-security/hostkey.pem\";\n            serverCert = \"/etc/grid-security/hostcert.pem\";\n            File certFile = new File(serverCert);\n            File keyFile = new File(serverKey);\n            // last, try to use user proxy, if it exists (currently disabled, look above)\n            if (!certFile.exists()) {\n                serverCert = null;\n            }\n            if (!keyFile.exists()) {\n                serverKey = null;\n            }\n        }\n\n        if (serverKey == null && serverCert == null) {\n            // no X509_HOST_* var, use client cert (proxy-cert)\n            credentials = X509Credential.getDefaultCredential();\n            if (logger.isLoggable(Level.INFO)) {\n                logger.log(Level.INFO, \"Using user proxy certificate:\" + credentials.getSubject());\n            }\n        } else if (serverKey != null && serverCert != null) {\n            credentials = new X509Credential(serverCert, serverKey);\n            if (logger.isLoggable(Level.INFO)) {\n                logger.log(Level.INFO, \"Using host certificate:\" + credentials.getSubject());\n            }\n        } else {\n            throw new IOException(\"Error: Service credentials could not be loaded.\");\n        }\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \"credentials:\" + credentials);\n        }\n        return new GlobusGSSCredentialImpl(credentials, GSSCredential.ACCEPT_ONLY);\n\n    }\n\n    // DEBUG\n    public static void main(String[] args) throws Exception {\n        GSIServer ctrlServer = new GSIServer();\n        ctrlServer.start();\n        System.out.println(\"Started\");\n    }\n\n    /**\n     * Initialization of the GSI server searching and setting the authorization plugin: <br>\n     * org.globus.gsi.gssapi.auth.AuthorizationPlugin system property may use to define the class implementing an GT2 Authorization Plugin.<br>\n     * If not defined the default grid-mapfile authorization method is used.\n     *\n     * @throws IOException\n     * @throws IOException if grid-map file cannot be loaded\n     * @see org.globus.gsi.gssapi.auth.Authorization\n     */\n\n    protected void initialize() {\n        super.initialize();\n        setGssMode(GSIConstants.MODE_GSI);\n    }\n\n    /**\n     * Handles individual client connections by starting a different thread.\n     *\n     * @param peer is connected to a client ready to send request to the gatekeeper.\n     * @throws IOException if authentication/authorization exception\n     */\n    protected void handleConnection(Peer peer) {\n        Socket socket = peer.getSocket();\n        Subject peerSubject = null;\n        if (logger.isLoggable(Level.FINE)) {\n            logger.info(\"Client connected: \" + socket.getInetAddress() + \":\" + socket.getPort());\n        }\n        // in order to start the SSL handshake we need to call socket.getInput(Output)Stream()\n        try {\n            socket.getOutputStream();\n            socket.getInputStream();\n            // peer.authorizer called\n            peerSubject = peer.getPeerSubject();\n        } catch (Throwable t) {\n            logger.log(Level.INFO, \"Authentication failed:\", t);\n            if (socket != null) {\n                if (logger.isLoggable(Level.INFO)) {\n                    logger.log(Level.INFO, \"Client disconnected\");\n                }\n                try {\n                    socket.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            return;\n        }\n\n        // the client is successfully authenticated and authorized\n        // so, proceed with the actual control conversation\n        handleConversation(this, socket, peerSubject);\n\n    }\n\n    /**\n     * This method needs to be implemented by subclasses. <br>\n     * Optimmaly, it should be a non-blocking call starting a separate thread to handle the client: i.e:\n     * <p>\n     * <pre>\n     *   ControlClient c = new ControlClient(parent, socket,Subject peerSubject);\n     *   c.start()\n     * </pre>\n     * <p>\n     * The default implementation just put an int on the wire.\n     */\n    protected void handleConversation(GSIServer parent, Socket client, Subject peerSubject) {\n        logger.info(\"Client connected :\" + client + \"\\n\" + peerSubject);\n        if (peerSubject != null) {\n            UserNamePrincipal up = (UserNamePrincipal) peerSubject.getPrincipals(UserNamePrincipal.class).toArray()[0];\n            System.out.println(\"LocalID:\" + up.getName());\n        }\n        try {\n            PrintWriter pw = new PrintWriter(client.getOutputStream());\n            pw.println(\"HELLO From GSI Server. Your order please!\");\n            pw.flush();\n            System.out.println(\"Sent\");\n            try {\n                Thread.sleep(10000);\n            } catch (InterruptedException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public String getContact() {\n        String gid = null;\n        try {\n            gid = getCredentials().getName().toString();\n        } catch (GSSException e) {\n            return null;\n        }\n\n        StringBuffer url = new StringBuffer();\n        url.append(getHost()).append(\":\").append(String.valueOf(getPort())).append(\":\").append(gid);\n\n        return url.toString();\n    }\n}\n"
  },
  {
    "path": "src/lia/gsi/authz/GridMap.java",
    "content": "/*\n * Portions of this file Copyright 1999-2005 University of Chicago\n * Portions of this file Copyright 1999-2005 The University of Southern California.\n *\n * This file or a portion of this file is licensed under the\n * terms of the Globus Toolkit Public License, found at\n * http://www.globus.org/toolkit/download/license.html.\n * If you redistribute this file, with or without\n * modifications, you must include this notice in the file.\n */\npackage lia.gsi.authz;\n\nimport org.globus.util.QuotedStringTokenizer;\n\nimport java.io.*;\nimport java.util.*;\n\npublic class GridMap implements Serializable {\n\n    public static final String DEFAULT_GRID_MAP = \"/etc/grid-security/grid-mapfile\";\n    private static final String COMMENT_CHARS = \"#\";\n    // keywords that need to be replaced\n    private static final char[] EMAIL_KEYWORD_1 = {'e', '='};\n    private static final char[] EMAIL_KEYWORD_2 = {'e', 'm', 'a', 'i', 'l', '='};\n    private static final char[] UID_KEYWORD = {'u', 'i', 'd', '='};\n    // Length of key words that need to be replaced\n    private static final int EMAIL_KEYWORD_1_L = 2;\n    private static final int EMAIL_KEYWORD_2_L = 6;\n    private static final int UID_KEYWORD_L = 4;\n    // Keywords to be replaced with.\n    private static final String EMAIL_KEYWORD = \"emailaddress=\";\n    private static final String USERID_KEYWORD = \"userid=\";\n    private static Map gridMaps = new HashMap();\n    protected Map map;\n\n    // the file the grim map was loaded from\n    private File file;\n    // last time the file was modified\n    private long lastModified;\n\n    /**\n     * Returns an instance of the default grid map. If an existing instance is already loaded, it is refreshed. The meaning of default grid map depends on the <i>grid.mapfile</i>\n     * system property. If the property is defined, this method attempts to load the map file from the file pointed to by the the property. If the \"grid.mapfile\" system property is\n     * not defined, the method attempts to load the map file from <code>/etc/grid-security/grid-mapfile.\n     *\n     * @return The default map file instance.\n     * @throws IOException if an error occurs while loading the default map file.\n     */\n    public static GridMap getGridMap() throws IOException {\n        // java property?\n        String mapFile = System.getProperty(\"GRIDMAP\");\n        // env var?\n        if (mapFile == null)\n            mapFile = System.getenv(\"GRIDMAP\");\n        // default one\n        if (mapFile == null)\n            mapFile = DEFAULT_GRID_MAP;\n\n        return getGridMap(mapFile);\n    }\n\n    /**\n     * Returns an instance of the grid map loaded from a specific file. If an instance was loaded previously (by calling this method with the same argument), it is refreshed and\n     * returned.\n     *\n     * @param mapFile the file from which the grid map is to be loaded\n     * @return The grid map file instance loaded from the specified file\n     * @throws IOException if an error occurs while loading the grid map file\n     */\n    public static synchronized GridMap getGridMap(String mapFile) throws IOException {\n        GridMap gridMap = (GridMap) gridMaps.get(mapFile);\n        if (gridMap == null) {\n            gridMap = new GridMap();\n            gridMap.load(mapFile);\n            gridMaps.put(mapFile, gridMap);\n        } else {\n            gridMap.refresh();\n        }\n        return gridMap;\n    }\n\n    private static boolean keyWordPresent(char[] args, int startIndex, char[] keyword, int length) {\n\n        if (startIndex + length > args.length) {\n            return false;\n        }\n\n        int j = startIndex;\n        for (int i = 0; i < length; i++) {\n            if (args[j] != keyword[i]) {\n                return false;\n            }\n            j++;\n        }\n        return true;\n    }\n\n    public static String normalizeDN(String globusID) {\n\n        if (globusID == null) {\n            return null;\n        }\n\n        globusID = globusID.toLowerCase();\n        char[] globusIdChars = globusID.toCharArray();\n\n        StringBuffer normalizedDN = new StringBuffer();\n\n        int i = 0;\n\n        while (i < globusIdChars.length) {\n\n            if (globusIdChars[i] == '/') {\n\n                normalizedDN.append(\"/\");\n\n                if (keyWordPresent(globusIdChars, i + 1, EMAIL_KEYWORD_1, EMAIL_KEYWORD_1_L)) {\n                    normalizedDN.append(EMAIL_KEYWORD);\n                    i = i + EMAIL_KEYWORD_1_L;\n                } else if (keyWordPresent(globusIdChars, i + 1, EMAIL_KEYWORD_2, EMAIL_KEYWORD_2_L)) {\n                    normalizedDN.append(EMAIL_KEYWORD);\n                    i = i + EMAIL_KEYWORD_2_L;\n                } else if (keyWordPresent(globusIdChars, i + 1, UID_KEYWORD, UID_KEYWORD_L)) {\n                    normalizedDN.append(USERID_KEYWORD);\n                    i = i + UID_KEYWORD_L;\n                }\n                i++;\n            } else {\n                normalizedDN.append(globusIdChars[i]);\n                i++;\n            }\n        }\n\n        return normalizedDN.toString();\n    }\n\n    /**\n     * Loads grid map definition from a given file.\n     *\n     * @param file grid map file\n     * @throws IOException in case of I/O or parsing error.\n     */\n    public void load(String file) throws IOException {\n        load(new File(file));\n    }\n\n    /**\n     * Loads grid map definition from a given file.\n     *\n     * @param file grid map file\n     * @throws IOException in case of I/O or parsing error.\n     */\n    public synchronized void load(File file) throws IOException {\n        InputStream in = null;\n        try {\n            in = new FileInputStream(file);\n            this.file = file;\n            this.lastModified = file.lastModified();\n            load(in);\n        } finally {\n            if (in != null) {\n                try {\n                    in.close();\n                } catch (Exception e) {\n                }\n            }\n        }\n    }\n\n    /**\n     * Reloads the gridmap from a file only if the gridmap was initially loaded using the {@link #load(File)  load} or {@link #load(String) load} functions. The file will only be\n     * reloaded if it has changed since the last time.\n     *\n     * @throws IOException in case of I/O error during reload.\n     */\n    public void refresh() throws IOException {\n        if (this.file == null) {\n            return;\n        }\n        if (this.file.lastModified() != this.lastModified) {\n            load(this.file);\n        }\n    }\n\n    /**\n     * Loads grid map file definition from a given input stream. The input stream is not closed in case of an error.\n     *\n     * @param input input stream containing grid map definitions.\n     * @throws IOException in case of I/O error or parsing error.\n     */\n    public void load(InputStream input) throws IOException {\n        String line;\n\n        BufferedReader reader = new BufferedReader(new InputStreamReader(input));\n\n        Map localMap = new HashMap();\n        GridMapEntry entry;\n        QuotedStringTokenizer tokenizer;\n        StringTokenizer idTokenizer;\n\n        while ((line = reader.readLine()) != null) {\n            line = line.trim();\n            if ((line.length() == 0) || (COMMENT_CHARS.indexOf(line.charAt(0)) != -1)) {\n                continue;\n            }\n\n            tokenizer = new QuotedStringTokenizer(line);\n\n            String globusID = null;\n\n            if (tokenizer.hasMoreTokens()) {\n                globusID = tokenizer.nextToken();\n            } else {\n                throw new IOException(\"Globus ID not defined: \" + line);\n            }\n\n            String userIDs = null;\n\n            if (tokenizer.hasMoreTokens()) {\n                userIDs = tokenizer.nextToken();\n            } else {\n                throw new IOException(\"User ID mapping missing: \" + line);\n            }\n\n            idTokenizer = new StringTokenizer(userIDs, \",\");\n            String[] ids = new String[idTokenizer.countTokens()];\n            int i = 0;\n            while (idTokenizer.hasMoreTokens()) {\n                ids[i++] = idTokenizer.nextToken();\n            }\n\n            String normalizedDN = normalizeDN(globusID);\n            entry = (GridMapEntry) localMap.get(normalizedDN);\n            if (entry == null) {\n                entry = new GridMapEntry();\n                entry.setGlobusID(globusID);\n                entry.setUserIDs(ids);\n                localMap.put(normalizedDN, entry);\n            } else {\n                entry.addUserIDs(ids);\n            }\n        }\n\n        map = localMap;\n    }\n\n    /**\n     * Returns first local user name mapped to the specified globusID.\n     *\n     * @param globusID globusID\n     * @return local user name for the specified globusID. Null if the globusID is not mapped to a local user name.\n     */\n    public synchronized String getUserID(String globusID) {\n        String[] ids = getUserIDs(globusID);\n        if (ids != null && ids.length > 0) {\n            return ids[0];\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Returns local user names mapped to the specified globusID.\n     *\n     * @param globusID globusID\n     * @return array of local user names for the specified globusID. Null if the globusID is not mapped to any local user name.\n     */\n    public synchronized String[] getUserIDs(String globusID) {\n        if (globusID == null) {\n            throw new IllegalArgumentException(\"globusID is null\");\n        }\n\n        if (map == null) {\n            // not initialized\n            // if not running as root, then return own username\n            // this allows someone to run as themselves without\n            // having to have a gridmap file.\n            String user = System.getProperty(\"user.name\");\n            if (user == null)\n                return null;\n            String tmpUser = user.toLowerCase();\n            if (tmpUser.equals(\"root\") || tmpUser.equals(\"administrator\")) {\n                return null;\n            } else {\n                return new String[]{user};\n            }\n        }\n\n        GridMapEntry entry = (GridMapEntry) map.get(normalizeDN(globusID));\n        return (entry == null)\n                ? null\n                : entry.getUserIDs();\n    }\n\n    /**\n     * Checks if a given globus ID is associated with given local user account.\n     *\n     * @param globusID globus ID\n     * @param userID   userID\n     * @return true if globus ID is associated with given local user account, false, otherwise.\n     */\n    public synchronized boolean checkUser(String globusID, String userID) {\n        if (globusID == null) {\n            throw new IllegalArgumentException(\"globusID is null\");\n        }\n        if (userID == null) {\n            throw new IllegalArgumentException(\"userID is null\");\n        }\n\n        if (map == null) {\n            // not initialized\n            // if not running as root, then return own username\n            // this allows someone to run as themselves without\n            // having to have a gridmap file.\n            String user = System.getProperty(\"user.name\");\n            if (user == null)\n                return false;\n            String tmpUser = user.toLowerCase();\n            if (tmpUser.equals(\"root\") || tmpUser.equals(\"administrator\")) {\n                return false;\n            } else {\n                return user.equalsIgnoreCase(userID);\n            }\n        }\n\n        GridMapEntry entry = (GridMapEntry) map.get(normalizeDN(globusID));\n        return (entry == null)\n                ? false\n                : entry.containsUserID(userID);\n    }\n\n    /**\n     * Returns globus ID associated with the specified local user name.\n     *\n     * @param userID local user name\n     * @return associated globus ID, null if there is not any.\n     */\n    public synchronized String getGlobusID(String userID) {\n        if (userID == null) {\n            throw new IllegalArgumentException(\"userID is null\");\n        }\n\n        if (map == null) {\n            return null;\n        }\n\n        Iterator iter = map.entrySet().iterator();\n        Map.Entry mapEntry;\n        GridMapEntry entry;\n        while (iter.hasNext()) {\n            mapEntry = (Map.Entry) iter.next();\n            entry = (GridMapEntry) mapEntry.getValue();\n            if (entry.containsUserID(userID)) {\n                return entry.getGlobusID();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns all globus IDs associated with the specified local user name.\n     *\n     * @param userID local user name\n     * @return associated globus ID, null if there is not any.\n     */\n    public synchronized String[] getAllGlobusID(String userID) {\n        if (userID == null) {\n            throw new IllegalArgumentException(\"userID is null\");\n        }\n\n        if (map == null) {\n            return null;\n        }\n\n        Vector v = new Vector();\n\n        Iterator iter = map.entrySet().iterator();\n        Map.Entry mapEntry;\n        GridMapEntry entry;\n        while (iter.hasNext()) {\n            mapEntry = (Map.Entry) iter.next();\n            entry = (GridMapEntry) mapEntry.getValue();\n            if (entry.containsUserID(userID)) {\n                v.add(entry.getGlobusID());\n            }\n        }\n\n        // create array of strings and add values back in\n        if (v.size() == 0) {\n            return null;\n        }\n\n        String idS[] = new String[v.size()];\n        for (int ctr = 0; ctr < v.size(); ctr++) {\n            idS[ctr] = (String) v.elementAt(ctr);\n        }\n\n        return idS;\n    }\n\n    public synchronized void map(String globusID, String userID) {\n        if (globusID == null) {\n            throw new IllegalArgumentException(\"globusID is null\");\n        }\n        if (userID == null) {\n            throw new IllegalArgumentException(\"userID is null\");\n        }\n\n        if (map == null) {\n            map = new HashMap();\n        }\n\n        String normalizedDN = normalizeDN(globusID);\n\n        GridMapEntry entry = (GridMapEntry) map.get(normalizedDN);\n        if (entry == null) {\n            entry = new GridMapEntry();\n            entry.setGlobusID(globusID);\n            entry.setUserIDs(new String[]{userID});\n            map.put(normalizedDN, entry);\n        } else {\n            entry.addUserID(userID);\n        }\n    }\n\n    static class GridMapEntry implements Serializable {\n        String globusID;\n        String[] userIDs;\n\n        public String getFirstUserID() {\n            return userIDs[0];\n        }\n\n        public String[] getUserIDs() {\n            return userIDs;\n        }\n\n        public void setUserIDs(String[] userIDs) {\n            this.userIDs = userIDs;\n        }\n\n        public String getGlobusID() {\n            return globusID;\n        }\n\n        public void setGlobusID(String globusID) {\n            this.globusID = globusID;\n        }\n\n        public boolean containsUserID(String userID) {\n            if (userID == null) {\n                return false;\n            }\n            for (int i = 0; i < userIDs.length; i++) {\n                if (userIDs[i].equalsIgnoreCase(userID)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        public void addUserID(String userID) {\n            if (containsUserID(userID))\n                return;\n            String[] ids = new String[userIDs.length + 1];\n            System.arraycopy(userIDs, 0, ids, 0, userIDs.length);\n            ids[userIDs.length] = userID;\n            userIDs = ids;\n        }\n\n        public void addUserIDs(String[] userIDs) {\n            for (int i = 0; i < userIDs.length; i++) {\n                addUserID(userIDs[i]);\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/lia/gsi/authz/GridMapAuthorization.java",
    "content": "//----------------------------------------------------------------------\n//This code is developed as part of the Java CoG Kit project\n//The terms of the license can be found at http://www.cogkit.org/license\n//This message may not be removed or altered.\n//----------------------------------------------------------------------\n\n/*\n * Created on Jul 19, 2005\n */\npackage lia.gsi.authz;\n\nimport org.globus.gsi.gssapi.auth.AuthorizationException;\nimport org.ietf.jgss.GSSContext;\nimport org.ietf.jgss.GSSException;\n\nimport java.io.IOException;\n\npublic class GridMapAuthorization extends LocalMappingAuthorization {\n\n    public GridMapAuthorization() throws IOException {\n        GridMap.getGridMap();\n    }\n\n    public String getLocalID(GSSContext context, String host) {\n        try {\n            String dn = context.getSrcName().toString();\n            String name = GridMap.getGridMap().getUserID(dn);\n\n            if (name == null) {\n                throw new AuthorizationException(\"No local mapping for \" + dn);\n            }\n            return name;\n        } catch (IOException e) {\n            return null;\n        } catch (GSSException e) {\n            return null;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/lia/gsi/authz/LocalMappingAuthorization.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi.authz;\n\nimport org.globus.gsi.gssapi.JaasGssUtil;\nimport org.globus.gsi.gssapi.auth.Authorization;\nimport org.globus.gsi.gssapi.auth.AuthorizationException;\nimport org.globus.gsi.gssapi.jaas.GlobusPrincipal;\nimport org.globus.gsi.gssapi.jaas.UserNamePrincipal;\nimport org.ietf.jgss.GSSContext;\nimport org.ietf.jgss.GSSException;\n\nimport javax.security.auth.Subject;\n\n/**\n * Extend org.globus.gsi.gssapi.auth.Authorization base-class to also provide the localID mapping of the client.<br>\n * This is based on PDP interface from GT4 but in the same time keep the backward-compatibily with  GT2 interfaces<br>\n * The default authorization plugin can be changed at runtime with other implementation of this class by passing:\n * <i>-Dgsi.authz.Authorization=authzclass</i> property.<br>\n * By default the GridMapAuthorization is used\n *\n * @author Adrian Muraru\n * @date 30.01.2007\n */\npublic abstract class LocalMappingAuthorization extends Authorization {\n\n    Subject peerSubject = null;\n\n    /**\n     * Interface for authorization mechanisms on server side\n     * The authorization is performed once the connection was authenticated.\n     *\n     * @return: local userID mapping for the given peer (ussualy based on DN) or \"null\" is the user is not authorized\n     */\n    public abstract String getLocalID(GSSContext context, String host);\n\n    public void authorize(GSSContext context, String host) throws AuthorizationException {\n\n        String localID = this.getLocalID(context, host);\n        if (localID == null) {\n            String srcName;\n            try {\n                srcName = context == null ? \"\" : context.getSrcName().toString();\n            } catch (GSSException e) {\n                srcName = \"\";\n            }\n            throw new AuthorizationException(\"No local mapping for :\" + srcName);\n        }\n        peerSubject = new Subject();\n        GlobusPrincipal nm;\n        try {\n            nm = JaasGssUtil.toGlobusPrincipal(context.getSrcName());\n        } catch (GSSException e) {\n            throw new AuthorizationException(\"Cannot get peer DN\");\n        }\n        peerSubject.getPrincipals().add(nm);\n        peerSubject.getPrincipals().add(new UserNamePrincipal(localID));\n    }\n\n    public Subject getPeerSubject() {\n        return this.peerSubject;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/gsi/net/GSIBaseServer.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi.net;\n\nimport lia.gsi.authz.LocalMappingAuthorization;\nimport org.globus.gsi.GSIConstants;\nimport org.globus.gsi.gssapi.GSSConstants;\nimport org.globus.gsi.gssapi.net.GssSocket;\nimport org.globus.gsi.gssapi.net.GssSocketFactory;\nimport org.globus.net.ServerSocketFactory;\nimport org.globus.net.SocketFactory;\nimport org.globus.util.Util;\nimport org.globus.util.deactivator.DeactivationHandler;\nimport org.globus.util.deactivator.Deactivator;\nimport org.gridforum.jgss.ExtendedGSSContext;\nimport org.gridforum.jgss.ExtendedGSSManager;\nimport org.ietf.jgss.GSSCredential;\nimport org.ietf.jgss.GSSException;\nimport org.ietf.jgss.GSSManager;\n\nimport java.io.IOException;\nimport java.net.*;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class provides the basics for writing various servers. <b>Note:</b> Sockets created by this server have a 5\n * minute default timeout. The timeout can be changed using the {@link #setTimeout(int) setTimeout()} function.\n *\n * @author Adrian Muraru\n */\npublic abstract class GSIBaseServer implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(GSIBaseServer.class.getName());\n\n    /**\n     * Socket timeout in milliseconds.\n     */\n    private static final int SO_TIMEOUT = Integer.getInteger(\"GSI_SO_TIMEOUT\", 5 * 60 * 1000);\n\n    protected volatile boolean accept;\n\n    protected ServerSocket _server = null;\n    protected String url = null;\n    protected GSSCredential credentials = null;\n    protected Integer gssMode = GSIConstants.MODE_SSL;\n    protected int timeout = SO_TIMEOUT;\n    /**\n     * A handler for the deactivation framework.\n     */\n    protected AbstractServerDeactivator deactivator = null;\n    /**\n     * This method should be called by all subclasses.\n     */\n    String authzClassName;\n    private Thread serverThread = null;\n    private boolean secure = true;\n\n    public GSIBaseServer() throws IOException {\n        this(null, 0);\n    }\n\n    public GSIBaseServer(final int port) throws IOException {\n        this(null, port);\n    }\n\n    public GSIBaseServer(final GSSCredential cred, final int port) throws IOException {\n        this.credentials = cred;\n        this._server = ServerSocketFactory.getDefault().createServerSocket(port);\n        this.secure = true;\n        initialize();\n    }\n\n    public GSIBaseServer(final boolean secure, final int port) throws IOException {\n        this.credentials = null;\n        this._server = ServerSocketFactory.getDefault().createServerSocket(port);\n        this.secure = secure;\n        initialize();\n    }\n\n    protected void initialize() {\n\n        authzClassName = System.getProperty(\"gsi.authz.Authorization\");\n        if (authzClassName == null) {\n            authzClassName = \"lia.gsi.authz.GridMapAuthorization\";\n        }\n    }\n\n    private LocalMappingAuthorization createAuthorizer() {\n        try {\n            final Class clazz = Class.forName(authzClassName);\n            if (!LocalMappingAuthorization.class.isAssignableFrom(clazz)) {\n                throw new RuntimeException(\"Invalid Server Authorization class\");\n            }\n            return (LocalMappingAuthorization) clazz.newInstance();\n        } catch (final ClassNotFoundException e) {\n            throw new RuntimeException(\"Unable to load '\" + authzClassName + \"' authorization plugin class. Cause: \" + e.getMessage());\n        } catch (final InstantiationException e) {\n            throw new RuntimeException(\"Unable to instantiate '\" + authzClassName + \"'authorization plugin class. Cause: \" + e.getMessage());\n        } catch (final IllegalAccessException e) {\n            throw new RuntimeException(\"Unable to instantiate '\" + authzClassName + \"'authorization plugin class. Cause: \" + e.getMessage());\n        } catch (Throwable t) {\n            throw new RuntimeException(\"Unable to instantiate '\" + authzClassName + \"'authorization plugin class. Cause: \" + t.getMessage());\n        }\n\n    }\n\n    public int getTimeout() {\n        return this.timeout;\n    }\n\n    /**\n     * Sets timeout for the created sockets. By default if not set, 5 minute timeout is used.\n     */\n    public void setTimeout(final int timeout) {\n        this.timeout = timeout;\n    }\n\n    /**\n     * Stops the server but does not stop all the client threads\n     */\n    public void shutdown() {\n        accept = false;\n        try {\n            _server.close();\n        } catch (final Exception e) {\n        }\n        // this is a hack to ensue the server socket is\n        // unblocked from accpet()\n        // but this is not guaranteed to work still\n        final SocketFactory factory = SocketFactory.getDefault();\n        Socket s = null;\n        try {\n            s = factory.createSocket(InetAddress.getLocalHost(), getPort());\n            s.getInputStream();\n        } catch (final Exception e) {\n            // can be ignored\n        } finally {\n            if (s != null) {\n                try {\n                    s.close();\n                } catch (final Exception e) {\n                }\n            }\n        }\n\n        // reset everything\n        serverThread = null;\n        _server = null;\n    }\n\n    /**\n     * Starts the server.\n     */\n    protected void start() {\n        if (serverThread == null) {\n            accept = true;\n            serverThread = new Thread(this);\n            serverThread.setName(\"GSIServer\");\n            serverThread.start();\n        }\n    }\n\n    public GSSCredential getCredentials() {\n        return this.credentials;\n    }\n\n    public String getProtocol() {\n        return (secure) ? \"https\" : \"http\";\n    }\n\n    /**\n     * Returns url of this server\n     *\n     * @return url of this server\n     */\n    public String getURL() {\n        if (url == null) {\n            final StringBuffer buf = new StringBuffer();\n            buf.append(getProtocol()).append(\"://\").append(getHost()).append(\":\").append(String.valueOf(getPort()));\n            url = buf.toString();\n        }\n        return url;\n    }\n\n    /**\n     * Returns port of this server\n     *\n     * @return port number\n     */\n    public int getPort() {\n        return _server.getLocalPort();\n    }\n\n    /**\n     * Returns hostname of this server\n     *\n     * @return hostname\n     */\n    public String getHostname() {\n        return Util.getLocalHostAddress();\n    }\n\n    /**\n     * Returns hostname of this server. The format of the host conforms to RFC 2732, i.e. for a literal IPv6 address,\n     * this method will return the IPv6 address enclosed in square\n     * brackets ('[' and ']').\n     *\n     * @return hostname\n     */\n    public String getHost() {\n        final String host = Util.getLocalHostAddress();\n        try {\n            final URL u = new URL(\"http\", host, 80, \"/\");\n            return u.getHost();\n        } catch (final MalformedURLException e) {\n            return host;\n        }\n    }\n\n    public void run() {\n        Socket socket = null;\n        boolean error = false;\n\n        while (accept) {\n            error = false;\n            socket = null;\n\n            try {\n                try {\n                    socket = _server.accept();\n                    if (!accept) {\n                        break;\n                    }\n                } catch (final IOException e) {\n                    if (accept) { // display error message\n                        logger.log(Level.WARNING, \"Server died: \" + e.getMessage(), e);\n                    }\n                    error = true;\n                    break;\n                }\n\n                if (socket == null) {\n                    continue;\n                }\n\n                try {\n                    socket.setSoTimeout(getTimeout());\n\n                    Peer peer = null;\n                    if (this.secure) {\n                        try {\n                            peer = wrapSocket(socket);\n                        } catch (final GSSException e) {\n                            logger.log(Level.WARNING, \"Failed to secure the socket\", e);\n                        }\n                    } else {\n                        peer = new Peer(socket, null);\n                    }\n\n                    handleConnection(peer);\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" [ GSIBaseServer ] Exception while trying to secure GSI socket: \" + socket, t);\n                    error = true;\n                }\n\n            } finally {\n                if (error && socket != null) {\n                    try {\n                        socket.close();\n                    } catch (Throwable ignore) {\n                    }\n                }\n            }\n\n        }\n\n        logger.log(Level.WARNING, \"server thread stopped\");\n    }\n\n    protected Peer wrapSocket(final Socket socket) throws GSSException {\n\n        final GSSManager manager = ExtendedGSSManager.getInstance();\n\n        final ExtendedGSSContext context = (ExtendedGSSContext) manager.createContext(credentials);\n\n        context.setOption(GSSConstants.GSS_MODE, gssMode);\n\n        final GssSocketFactory factory = GssSocketFactory.getDefault();\n\n        final GssSocket gsiSocket = (GssSocket) factory.createSocket(socket, null, 0, context);\n        // server socket\n        gsiSocket.setUseClientMode(false);\n\n        final LocalMappingAuthorization authorizer = createAuthorizer();\n        gsiSocket.setAuthorization(authorizer);\n\n        return new Peer(gsiSocket, authorizer);\n    }\n\n    public void setGssMode(final Integer mode) {\n        this.gssMode = mode;\n    }\n\n    public void setAuthorizationClass(final String auth) {\n        authzClassName = auth;\n    }\n\n    /**\n     * This method needs to be implemented by subclasses. <br>\n     * Optimmaly, it should be a non-blocking call starting a separate thread to handle the client. <br>\n     * Note that to start an SSL handshake, you need to call socket.getInput(Output) stream().\n     */\n    protected abstract void handleConnection(Peer peer);\n\n    /**\n     * Registers a default deactivation handler. It is used to shutdown the server without having a reference to the\n     * server. <br>\n     * Call Deactivate.deactivateAll() to shutdown all registered servers.\n     */\n    public void registerDefaultDeactivator() {\n        if (deactivator == null) {\n            deactivator = new AbstractServerDeactivator(this);\n        }\n        Deactivator.registerDeactivation(deactivator);\n    }\n\n    /**\n     * Unregisters a default deactivation handler.\n     */\n    public void unregisterDefaultDeactivator() {\n        if (deactivator == null)\n            return;\n        Deactivator.unregisterDeactivation(deactivator);\n    }\n\n}\n\nclass AbstractServerDeactivator implements DeactivationHandler {\n\n    private GSIBaseServer server = null;\n\n    public AbstractServerDeactivator(GSIBaseServer server) {\n        this.server = server;\n    }\n\n    public void deactivate() {\n        if (server != null)\n            server.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "src/lia/gsi/net/GSIGssSocketFactory.java",
    "content": "/*\n * Copyright 1999-2006 University of Chicago\n * \n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * \n * http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage lia.gsi.net;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.globus.common.CoGProperties;\nimport org.globus.gsi.CredentialException;\nimport org.globus.gsi.GSIConstants;\nimport org.globus.gsi.GlobusCredentialException;\nimport org.globus.gsi.X509Credential;\nimport org.globus.gsi.gssapi.GSSConstants;\nimport org.globus.gsi.gssapi.GlobusGSSCredentialImpl;\nimport org.globus.gsi.gssapi.JaasGssUtil;\nimport org.globus.gsi.gssapi.jaas.GlobusPrincipal;\nimport org.globus.gsi.gssapi.net.GssSocket;\nimport org.globus.gsi.gssapi.net.GssSocketFactory;\nimport org.globus.gsi.gssapi.net.impl.GSIGssSocket;\nimport org.gridforum.jgss.ExtendedGSSContext;\nimport org.gridforum.jgss.ExtendedGSSManager;\nimport org.ietf.jgss.*;\n\nimport javax.security.auth.Subject;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\n\n// additional GSIGssSocketFactory that may be selected using\n// -Dorg.globus.gsi.gssapi.net.provider\npublic class GSIGssSocketFactory extends GssSocketFactory {\n\n    private static final int GSI_CONNECT_TIMEOUT = Integer.getInteger(\"GSI_CONNECT_TIMEOUT\", 20 * 1000);\n\n    private static final Log logger = LogFactory.getLog(GSIGssSocketFactory.class.getName());\n\n    /**\n     * @param inetAddress    :\n     *                       the remote address\n     * @param port           :\n     *                       the remote port\n     * @param doDelegation   :\n     *                       if true, the client credential is delegated\n     * @param fullDelegation :\n     *                       if doDelegation is set, this parameter specifies the type of delegation (FULL or LIMITED)\n     * @return the GSI-protected socket connected to the remote host\n     * @throws IOException\n     */\n    public static java.net.Socket createSocket(java.net.InetAddress inetAddress, int port, boolean doDelegation, boolean fullDelegation)\n            throws IOException {\n        // raw socket\n        Socket socket = null;\n        try {\n            //override the search path for the CA directory: (GSI-SSHTERM writes in the ~/.globus/certificates so we don;t use this)\n            //1) java X509_CERT_DIR property\n            //2) override with X509_CERT_DIR env var\n            //3) default /etc/grid-security/certificates\n            String x509CertDir = System.getProperty(\"X509_CERT_DIR\");\n            if (x509CertDir == null) {\n                x509CertDir = System.getenv(\"X509_CERT_DIR\");\n                if (x509CertDir == null)\n                    x509CertDir = \"/etc/grid-security/certificates\";\n                System.setProperty(\"X509_CERT_DIR\", x509CertDir);\n            }\n\n            String x509UserProxy = System.getenv(\"X509_USER_PROXY\");\n            if (x509UserProxy == null)\n                x509UserProxy = CoGProperties.getDefault().getProxyFile();\n            System.out.println(\"Trying \" + x509UserProxy);\n            GSSCredential credential = createUserCredential(x509UserProxy);\n            if (credential == null) {\n                throw new IOException(\"User credential not initialized !\");\n            }\n\n            logger.info(\"createSocket() user credential is \" + credential.getName());\n            GSSManager manager = ExtendedGSSManager.getInstance();\n            org.globus.gsi.gssapi.auth.GSSAuthorization gssAuth = org.globus.gsi.gssapi.auth.HostAuthorization.getInstance();\n            GSSName targetName = gssAuth.getExpectedName(null, inetAddress.getCanonicalHostName());\n            ExtendedGSSContext context = (ExtendedGSSContext) manager.createContext(targetName, GSSConstants.MECH_OID, credential,\n                    GSSContext.DEFAULT_LIFETIME);\n            context.setOption(GSSConstants.GSS_MODE, GSIConstants.MODE_GSI);\n            context.requestCredDeleg(doDelegation);\n            if (doDelegation) {\n\n                if (fullDelegation) {\n                    context.setOption(GSSConstants.DELEGATION_TYPE, GSIConstants.DELEGATION_TYPE_FULL);\n                } else {\n                    context.setOption(GSSConstants.DELEGATION_TYPE, GSIConstants.DELEGATION_TYPE_LIMITED);\n                }\n            }\n\n            SocketAddress socketAddress = new InetSocketAddress(inetAddress, port);\n            socket = new Socket();\n            socket.connect(socketAddress, GSI_CONNECT_TIMEOUT);\n            GSIGssSocket gsiSocket = new GSIGssSocket(socket, context);\n            gsiSocket.setUseClientMode(true);\n            gsiSocket.setAuthorization(gssAuth);\n            // Should be GSI_MODE ?\n            gsiSocket.setWrapMode(GssSocket.SSL_MODE);\n            gsiSocket.startHandshake();\n            socket = gsiSocket;\n        } catch (Throwable e) {\n            if (socket != null) {\n                try {\n                    socket.close();\n                } catch (Throwable ignore) {\n                }\n            }\n            throw new IOException(e);\n        }\n        // return the wrapped socket\n        return socket;\n\n    }\n\n    /**\n     * Retrieve the Globus Subject from a GssSocket\n     *\n     * @param socket\n     * @return javax.security.auth.Subject having a single Principal elementt : The Globus DN\n     * @throws GSSException if the supplied socket is not a GssSocket or the Globus Credentials is not set on the socket\n     */\n    public static Subject getLocalSubject(Socket socket) throws GSSException {\n\n        if (!(socket instanceof GssSocket))\n            throw new GSSException(GSSException.NO_CRED);\n\n        GssSocket gssSocket;\n        gssSocket = (GssSocket) socket;\n        Subject mySubject = new Subject();\n        GlobusPrincipal nm;\n        try {\n            nm = JaasGssUtil.toGlobusPrincipal(gssSocket.getContext().getSrcName());\n        } catch (Throwable t) {\n            throw new GSSException(GSSException.NO_CRED);\n        }\n        mySubject.getPrincipals().add(nm);\n        return mySubject;\n    }\n\n    public static GSSCredential createUserCredential(String x509UserProxy) throws GlobusCredentialException, GSSException, CredentialException {\n        if (x509UserProxy != null) {\n            X509Credential gcred = new X509Credential(x509UserProxy);\n            GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n            return cred;\n        }\n        X509Credential gcred = X509Credential.getDefaultCredential();\n        GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n        return cred;\n\n    }\n\n    public static GSSCredential createUserCredential(String x509ServiceCert, String x509ServiceKey) throws GlobusCredentialException,\n            GSSException, CredentialException, IOException {\n        if (x509ServiceCert != null && x509ServiceKey != null) {\n            X509Credential gcred = new X509Credential(x509ServiceCert, x509ServiceKey);\n            GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n            return cred;\n        }\n\n        X509Credential gcred = X509Credential.getDefaultCredential();\n        GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n        return cred;\n    }\n\n    public Socket createSocket(Socket s, String host, int port, GSSContext context) {\n        return new GSIGssSocket(s, context);\n    }\n\n    public Socket createSocket(String host, int port, GSSContext context) throws IOException {\n        return new GSIGssSocket(host, port, context);\n    }\n\n}\n"
  },
  {
    "path": "src/lia/gsi/net/Peer.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi.net;\n\nimport lia.gsi.authz.LocalMappingAuthorization;\n\nimport javax.security.auth.Subject;\nimport java.net.Socket;\n\n/**\n * Extended Socket with an optional Subject attribute. The Subject field may contain additional Principal such as: GridID,UserLocalPrincipal\n *\n * @author Adrian Muraru\n */\npublic class Peer {\n    private final Socket socket;\n    private final LocalMappingAuthorization authorization;\n\n    public Peer(Socket socket, LocalMappingAuthorization authz) {\n        this.socket = socket;\n        this.authorization = authz;\n    }\n\n    public Socket getSocket() {\n        return this.socket;\n    }\n\n    public Subject getPeerSubject() {\n        return this.authorization == null ? null : this.authorization.getPeerSubject();\n    }\n\n}"
  },
  {
    "path": "src/lia/gsi/ssh/GSIAuthenticationClient.java",
    "content": "package lia.gsi.ssh;\n\n/**\n * Copyright (c) 2004, National Research Council of Canada All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish,\n * distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright\n * notice(s) and this licence appear in all copies of the Software or substantial portions of the Software, and that both the above copyright notice(s) and this license appear in\n * supporting documentation. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR\n * ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\n * OR PROFITS; OR BUSINESS INTERRUPTION) HOWSOEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n * OTHERWISE) ARISING IN ANY WAY OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Except as contained in\n * this notice, the name of a copyright holder shall NOT be used in advertising or otherwise to promote the sale, use or other dealings in this Software without specific prior\n * written authorization. Title to copyright in this software and any associated documentation will at all times remain with copyright holders.\n */\n// (Changes (c) CCLRC 2006)\n// (Changes Adi.Muraru 2007 - avoid GUIs dependencies, and rely on environment to get the proxy location)\n\nimport com.sshtools.j2ssh.authentication.*;\nimport com.sshtools.j2ssh.io.ByteArrayReader;\nimport com.sshtools.j2ssh.io.ByteArrayWriter;\nimport com.sshtools.j2ssh.io.UnsignedInteger32;\nimport org.globus.common.CoGProperties;\nimport org.globus.gsi.CredentialException;\nimport org.globus.gsi.GSIConstants;\nimport org.globus.gsi.GlobusCredentialException;\nimport org.globus.gsi.X509Credential;\nimport org.globus.gsi.gssapi.GSSConstants;\nimport org.globus.gsi.gssapi.GlobusGSSCredentialImpl;\nimport org.globus.gsi.gssapi.GlobusGSSManagerImpl;\nimport org.globus.gsi.gssapi.auth.HostAuthorization;\nimport org.gridforum.jgss.ExtendedGSSContext;\nimport org.ietf.jgss.*;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Properties;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic class GSIAuthenticationClient extends SshAuthenticationClient {\n\n    private static Logger logger = Logger.getLogger(GSIAuthenticationClient.class.getName());\n\n    GSSCredential gsscredential;\n\n    public GSIAuthenticationClient() throws GSSException, IOException {\n\n        //override the search path for the CA directory: (GSI-SSHTERM writes in the ~/.globus/certificates so we don;t use this)\n        //1) java X509_CERT_DIR property\n        //2) override with X509_CERT_DIR env var\n        //3) default /etc/grid-security/certificates\n        String x509CertDir = System.getProperty(\"X509_CERT_DIR\");\n        if (x509CertDir == null) {\n            x509CertDir = System.getenv(\"X509_CERT_DIR\");\n            if (x509CertDir == null)\n                x509CertDir = \"/etc/grid-security/certificates\";\n            System.setProperty(\"X509_CERT_DIR\", x509CertDir);\n        }\n\n        String x509UserProxy = System.getProperty(\"X509_USER_PROXY\");\n        if (x509UserProxy == null) {\n            x509UserProxy = System.getenv(\"X509_USER_PROXY\");\n            if (x509UserProxy != null)\n                System.setProperty(\"X509_USER_PROXY\", x509UserProxy);\n        }\n        if (x509UserProxy == null)\n            x509UserProxy = CoGProperties.getDefault().getProxyFile();\n        if (!new File(x509UserProxy).isFile())\n            throw new IOException(\"User proxy certificate not found in environment\");\n\n        logger.info(\"Using proxy certificate:\" + x509UserProxy);\n\n        try {\n            gsscredential = createUserCredential(x509UserProxy);\n        } catch (GlobusCredentialException | CredentialException e) {\n            throw new IOException(\"Could not load user proxy certificate from:\" + x509UserProxy);\n        }\n        if (gsscredential == null) {\n            throw new IOException(\"User credential not initialized !Could not load user proxy certificate. Check your environmen if you have X509_USER_CERT proxy set up\");\n        }\n    }\n\n    public static GSSCredential createUserCredential(String x509UserProxy) throws GlobusCredentialException, GSSException, CredentialException {\n        if (x509UserProxy != null) {\n            X509Credential gcred = new X509Credential(x509UserProxy);\n            GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n            return cred;\n        }\n        X509Credential gcred = X509Credential.getDefaultCredential();\n        GSSCredential cred = new GlobusGSSCredentialImpl(gcred, GSSCredential.INITIATE_ONLY);\n        return cred;\n\n    }\n\n    public final String getMethodName() {\n        return \"gssapi\";\n    }\n\n    public void reset() {\n    }\n\n    public void authenticate(AuthenticationProtocolClient authenticationprotocolclient, String s) throws IOException, TerminatedStateException {\n        try {\n            logger.finest(\"Registering gss-ssh return messages.\");\n            authenticationprotocolclient.registerMessage(com.sshtools.j2ssh.authentication.SshMsgUserauthGssapiResponse.class, 60);\n            authenticationprotocolclient.registerMessage(com.sshtools.j2ssh.authentication.SshMsgUserauthGssapiToken.class, 61);\n            authenticationprotocolclient.registerMessage(com.sshtools.j2ssh.authentication.SshMsgUserauthGssapiError.class, 64);\n            authenticationprotocolclient.registerMessage(com.sshtools.j2ssh.authentication.SshMsgUserauthGssapiErrtok.class, 65);\n            logger.finest(\"Sending gssapi user auth request.\");\n            ByteArrayWriter bytearraywriter = new ByteArrayWriter();\n            bytearraywriter.writeUINT32(new UnsignedInteger32(1L));\n            byte abyte0[] = GSSConstants.MECH_OID.getDER();\n            bytearraywriter.writeBinaryString(abyte0);\n            logger.finest(\"Username:\" + getUsername());\n            SshMsgUserAuthRequest sshmsguserauthrequest = new SshMsgUserAuthRequest(getUsername(), s, \"gssapi\", bytearraywriter.toByteArray());\n            authenticationprotocolclient.sendMessage(sshmsguserauthrequest);\n            logger.finest(\"Receiving user auth response:\");\n            SshMsgUserauthGssapiResponse sshmsguserauthgssapiresponse = (SshMsgUserauthGssapiResponse) authenticationprotocolclient.readMessage(60);\n            ByteArrayReader bytearrayreader = new ByteArrayReader(sshmsguserauthgssapiresponse.getRequestData());\n            byte abyte1[] = bytearrayreader.readBinaryString();\n            if (logger.isLoggable(Level.FINEST)) {\n                logger.log(Level.FINEST, \"Mechanism requested: \" + GSSConstants.MECH_OID);\n                logger.log(Level.FINEST, \"Mechanism selected: \" + new Oid(abyte1));\n                logger.log(Level.FINEST, \"Verify that selected mechanism is GSSAPI.\");\n            }\n            if (!GSSConstants.MECH_OID.equals(new Oid(abyte1))) {\n                logger.warning(\"Mechanism do not match!\");\n                throw new IOException(\"Mechanism do not match!\");\n            }\n            logger.finest(\"Creating GSS context base on grid credentials.\");\n            GlobusGSSManagerImpl globusgssmanagerimpl = new GlobusGSSManagerImpl();\n\n            HostAuthorization gssAuth = new HostAuthorization(null);\n            GSSName targetName = gssAuth.getExpectedName(null, hostname);\n\n            GSSContext gsscontext = globusgssmanagerimpl.createContext(targetName, new Oid(abyte1), gsscredential, GSSCredential.INDEFINITE_LIFETIME - 1);\n            gsscontext.requestCredDeleg(true);\n            gsscontext.requestMutualAuth(true);\n            gsscontext.requestReplayDet(true);\n            gsscontext.requestSequenceDet(true);\n            // MOD\n            // gsscontext.requestConf(false);\n            gsscontext.requestConf(true);\n\n            Object type = GSIConstants.DELEGATION_TYPE_LIMITED;\n            gsscontext.requestCredDeleg(false);\n            ((ExtendedGSSContext) gsscontext).setOption(GSSConstants.DELEGATION_TYPE, type);\n\n            logger.finest(\"Starting GSS token exchange.\");\n            byte abyte2[] = new byte[0];\n            do {\n                if (gsscontext.isEstablished())\n                    break;\n                byte abyte3[] = gsscontext.initSecContext(abyte2, 0, abyte2.length);\n                if (abyte3 != null) {\n                    ByteArrayWriter bytearraywriter1 = new ByteArrayWriter();\n                    bytearraywriter1.writeBinaryString(abyte3);\n                    SshMsgUserauthGssapiToken sshmsguserauthgssapitoken = new SshMsgUserauthGssapiToken(bytearraywriter1.toByteArray());\n                    authenticationprotocolclient.sendMessage(sshmsguserauthgssapitoken);\n                }\n                if (!gsscontext.isEstablished()) {\n                    SshMsgUserauthGssapiToken sshmsguserauthgssapitoken1 = (SshMsgUserauthGssapiToken) authenticationprotocolclient.readMessage(61);\n                    ByteArrayReader bytearrayreader1 = new ByteArrayReader(sshmsguserauthgssapitoken1.getRequestData());\n                    abyte2 = bytearrayreader1.readBinaryString();\n                }\n            } while (true);\n            logger.log(Level.FINEST, \"Sending gssapi exchange complete.\");\n            SshMsgUserauthGssapiExchangeComplete sshmsguserauthgssapiexchangecomplete = new SshMsgUserauthGssapiExchangeComplete();\n            authenticationprotocolclient.sendMessage(sshmsguserauthgssapiexchangecomplete);\n            if (logger.isLoggable(Level.FINEST)) {\n                logger.log(Level.FINEST, \"Context established.\\nInitiator : \" + gsscontext.getSrcName() + \"\\nAcceptor  : \" + gsscontext.getTargName() + \"\\nLifetime  : \"\n                        + gsscontext.getLifetime() + \"\\nIntegrity   : \" + gsscontext.getIntegState() + \"\\nConfidentiality   : \" + gsscontext.getConfState() + \"\\nAnonymity : \"\n                        + gsscontext.getAnonymityState());\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got Exception: \", t);\n            throw new TerminatedStateException(AuthenticationProtocolState.FAILED);\n        }\n    }\n\n    public Properties getPersistableProperties() {\n        Properties properties = new Properties();\n        return properties;\n    }\n\n    public void setPersistableProperties(Properties properties) {\n    }\n\n    public boolean canAuthenticate() {\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/gsi/ssh/TextSSHClient.java",
    "content": "/*\n * $Id$\n */\npackage lia.gsi.ssh;\n\nimport com.sshtools.common.configuration.SshToolsConnectionProfile;\nimport com.sshtools.j2ssh.SshClient;\nimport com.sshtools.j2ssh.authentication.AuthenticationProtocolState;\nimport com.sshtools.j2ssh.session.SessionChannelClient;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\n\n/**\n * @author Adrian Muraru\n */\npublic class TextSSHClient {\n\n    public static void main(String[] args) throws Exception {\n        GSIAuthenticationClient gsiAuth = null;\n        try {\n            gsiAuth = new GSIAuthenticationClient();\n            gsiAuth.setUsername(args[1]);\n        } catch (Exception e) {\n            System.err.println(\"Cannot load grid credentials.\");\n            e.printStackTrace();\n            return;\n        }\n        System.out.println(\"Local GSI Credential loaded.\");\n\n        SshClient ssh = new SshClient();\n        SshToolsConnectionProfile properties = new SshToolsConnectionProfile();\n        properties.setPort(1975);\n        properties.setForwardingAutoStartMode(false);\n        properties.setHost(args[0]);\n        properties.setUsername(args[1]);\n        ssh.setUseDefaultForwarding(false);\n        ssh.connect(properties);\n        System.out.println(\"Available methods:\" + ssh.getAvailableAuthMethods(args[1]));\n        try {\n            // Authenticate the user\n            int result = ssh.authenticate(gsiAuth, args[0]);\n            if (result != AuthenticationProtocolState.COMPLETE) {\n                // Authentication complete\n                System.out.println(\"Auth failed:\" + result);\n                return;\n            }\n            // Open a session channel\n            SessionChannelClient session = ssh.openSessionChannel();\n            session.requestPseudoTerminal(\"ansi\", 0, 0, 0, 0, \"\");\n            if (!session.executeCommand(args[2])) {\n                System.out.println(\"Command failed\");\n                ssh.disconnect();\n                return;\n            }\n            BufferedReader bfr = new BufferedReader(new InputStreamReader(session.getInputStream()));\n            String line;\n            while ((line = bfr.readLine()) != null)\n                System.out.println(line);\n        } catch (Exception e) {\n            e.printStackTrace();\n            ssh.disconnect();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/AbstractBPool.java",
    "content": "/*\n * Created on Nov 11, 2009\n */\npackage lia.util.net.common;\n\nimport java.nio.ByteBuffer;\nimport java.util.IdentityHashMap;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport sun.misc.Unsafe;\nimport java.lang.reflect.Field;\nimport java.nio.Buffer;\n\n/**\n * This class should unify both header and payload buffers\n *\n * @author ramiro\n */\npublic abstract class AbstractBPool {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(AbstractBPool.class.getName());\n\n    protected final int bufferSize;\n\n    protected final int maxPollIter;\n\n    protected final BlockingQueue<ByteBuffer> thePool;\n    protected final AtomicBoolean limitReached = new AtomicBoolean(false);\n    protected final AtomicInteger poolSize = new AtomicInteger(0);\n    protected final boolean randomGen;\n    private final boolean trackAllocations;\n    private final IdentityHashMap<ByteBuffer, AtomicBoolean> mapTrack = new IdentityHashMap<ByteBuffer, AtomicBoolean>();\n\n    public AbstractBPool(int bufferSize, int maxPollIter) {\n        this(bufferSize, maxPollIter, false);\n    }\n\n    public AbstractBPool(int bufferSize, int maxPollIter, boolean trackAllocations) {\n        this(bufferSize, maxPollIter, trackAllocations, false);\n    }\n\n    public AbstractBPool(int bufferSize, int maxPollIter, boolean trackAllocations, boolean randomGen) {\n        this.bufferSize = bufferSize;\n        this.maxPollIter = maxPollIter;\n        thePool = new LinkedBlockingQueue<ByteBuffer>();\n        this.trackAllocations = trackAllocations;\n        this.randomGen = randomGen;\n\n        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {\n            final ByteBuffer bb = tryAllocateBuffer();\n            if (bb != null) {\n                thePool.offer(bb);\n            }\n        }\n\n        if (poolSize.get() == 0) {\n            // nasty nasty - zorro e pe lemne ( System.exit() ?? )\n            logger.log(Level.WARNING, \" \\n\\n\\n\\n !!!! Unable to allocate any buffers to the pool .... FDT will not work .... !!!! \\n\\n\\n\\n \");\n            // System.exit(1);\n        }\n\n    }\n\n    // Align all buffes to a 4K boundary.  This is a safe operation for all file accesses.\n    // By aligning, we allow for O_DIRECT accesses (using the LD_PRELOAD open_direct.c shim)\n    // which can be 0-copy and do not pollute the page cache with data that will only be\n    // streamed one time.  If the LD_PRELOAD shim is not used, or the buffer is for a file\n    // which is not opened in direct mode, there is no logical change to system operation.\n    //\n    // Adapted from http://psy-lob-saw.blogspot.com/2013/01/direct-memory-alignment-in-java.html\n    private static Unsafe unsafe;      // Only way to access addresses of ByteBuffer data\n    private static long addressOffset; // The offsetof(Buffer.address)\n    // Class initialization needs to set the above variables\n    {\n        // If we directly try to get an Unsafe singleton, we'll throw a security exception,\n        // so go into the class itself and mark the field accessible and then grab it.\n        try {\n            Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            unsafe = (Unsafe) f.get(null);\n\t} catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        // Unsafe is available, so cache the offsetof(address) we need\n        try {\n            Field[] f = Buffer.class.getDeclaredFields();\n            boolean found = false;\n            for (int i = 0; i < f.length; i++) { // Dumb, but only run once over small list\n                if (f[i].toString().compareTo(\"long java.nio.Buffer.address\") == 0) {\n                    addressOffset = unsafe.objectFieldOffset(f[i]);\n                    found = true;\n                }\n            }\n            if (found == false) {\n                throw new RuntimeException(\"Can't find Buffer.address field\");\n            }\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    // Peek at this Buffer.address, pointing to the actual data for this ByteBuffer\n    private static long getAddress(ByteBuffer buffy) {\n        return unsafe.getLong(buffy, addressOffset);\n    }\n\n    // Allocate ByteBuffer with data aligned to a specific alignment.  Works for any\n    // 2^n alignment, but in this case we only need 4096 (i.e. page aligned).\n    private static ByteBuffer allocateAlignedByteBuffer(int capacity, long align) {\n        // Power of 2 --> single bit, none power of 2 alignments are not allowed.\n        if (Long.bitCount(align) != 1) {\n            throw new IllegalArgumentException(\"Alignment must be a power of 2\");\n        }\n        // We over allocate by the alignment so we know we can have a large enough aligned\n        // block of memory to use. Also set order to native while we are here.\n        ByteBuffer buffy = ByteBuffer.allocateDirect((int) (capacity + align));\n        long address = getAddress(buffy);\n        // check if we got lucky and the address is already aligned\n        if ((address & (align - 1)) == 0) {\n            // set the new limit to intended capacity\n            buffy.limit(capacity);\n            // the slice is now an aligned buffer of the required capacity\n           return buffy.slice();//.order(ByteOrder.nativeOrder());\n        } else {\n            // we need to shift the start position to an aligned address --> address + (align - (address % align))\n            // the modulo replacement with the & trick is valid for power of 2 values only\n            int newPosition = (int) (align - (address & (align - 1)));\n            // change the position\n            buffy.position(newPosition);\n            int newLimit = newPosition + capacity;\n            // set the new limit to accomodate offset + intended capacity\n            buffy.limit(newLimit);\n            // the slice is now an aligned buffer of the required capacity\n            return buffy.slice();//.order(ByteOrder.nativeOrder());\n        }\n    }\n\n    private ByteBuffer tryAllocateBuffer() {\n\n        ByteBuffer retBuffer = null;\n        try {\n            retBuffer = allocateAlignedByteBuffer(bufferSize, 4096);\n            if (randomGen && retBuffer != null) {\n                try {\n                    logger.log(Level.INFO, \"BuffFill START generating data to fill the buffer: \" + Utils.buffToString(retBuffer));\n                    Random r = new Random();\n                    byte[] bBuf = new byte[retBuffer.capacity()];\n                    r.nextBytes(bBuf);\n                    retBuffer.clear();\n                    retBuffer.put(bBuf);\n                    logger.log(Level.INFO, \"BuffFill END generating data to fill the buffer: \" + Utils.buffToString(retBuffer));\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Unable to generate data to fill the buffer\", t);\n                }\n            }\n        } catch (OutOfMemoryError oom) {\n            if (limitReached.compareAndSet(false, true)) {\n                logger.log(Level.WARNING, \"\\n\\n !! Direct ByteBuffer memory pool reached max limit. Allocated: \"\n                        + (totalAllocated() + totalAllocated()) / (1024 * 1024) + \" MB.\"\n                        + \"\\n FDT reuses the existing buffers, but the copy may be slow!!\"\n                        + \"\\n You may consider to increase the default value used by the JVM ( e.g. -XX:MaxDirectMemorySize=256m ),\"\n                        + \"\\n or decrease either the buffer size( -bs param) or the number of workers (-P param) \\n\\n\\n\");\n            }\n            retBuffer = null;\n        } catch (Throwable t) {\n            logger.log(Level.SEVERE, \" Got general exception trying to allocate the mem. Please notify the developers! \", t);\n            retBuffer = null;\n        } finally {\n            if (retBuffer != null) {\n                poolSize.incrementAndGet();\n                if (trackAllocations) {\n                    synchronized (mapTrack) {\n                        mapTrack.put(retBuffer, new AtomicBoolean(false));\n                    }\n                }\n            }\n        }\n\n        return retBuffer;\n    }\n\n    /**\n     * @return - Total direct memory allocated by the pool\n     */\n    public final long totalAllocated() {\n        return poolSize.get() * bufferSize;\n    }\n\n    public ByteBuffer take() throws InterruptedException {\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        final boolean logFiner = logFinest || logger.isLoggable(Level.FINER);\n\n        ByteBuffer retBuff = thePool.poll();\n        try {\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = tryAllocateBuffer();\n\n            if (retBuff == null) {\n                for (int i = 0; i < maxPollIter; i++) {\n                    retBuff = thePool.poll();\n                    if (retBuff != null) {\n                        break;\n                    }\n                }\n            }\n\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = thePool.take();\n\n            return retBuff;\n        } finally {\n            if (retBuff != null) {\n                retBuff.clear();\n            }\n            if (logFiner) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"<ByteBufferPool> TAKE FROM POOL in poll(): buffer: \").append(Utils.buffToString(retBuff));\n                sb.append(\"; qSize: \").append(thePool.size()).append(\" allocSize: \").append(poolSize.get());\n                if (logFinest) {\n                    sb.append(\" Trace: \");\n                    logger.log(Level.INFO, sb.toString(), new Throwable());\n                } else {\n                    logger.log(Level.INFO, sb.toString());\n                }\n            }\n            if (trackAllocations && retBuff != null) {\n                if (!checkBuffer(retBuff, false, true)) {\n                    logger.log(Level.WARNING, \" \\n\\n  <ByteBufferPool> trackAllocations ASSERTION FAILURE. retBuf = \" + Utils.buffToString(retBuff)\n                            + \"; TAKE FROM POOL! expect: false update: true\", new Exception(\"ASSERTION_FAILURE\"));\n                }\n            }\n        }\n\n    }\n\n    private final boolean checkBuffer(final ByteBuffer bb, final boolean expect, final boolean update) {\n        synchronized (mapTrack) {\n            final AtomicBoolean inUse = mapTrack.get(bb);\n            if (inUse == null) {\n                return false;\n            }\n\n            return inUse.compareAndSet(expect, update);\n        }\n    }\n\n    public ByteBuffer poll() {\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        final boolean logFiner = logFinest || logger.isLoggable(Level.FINER);\n\n        ByteBuffer retBuff = thePool.poll();\n        try {\n\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = tryAllocateBuffer();\n\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = thePool.poll();\n            return retBuff;\n        } finally {\n            if (retBuff != null) {\n                retBuff.clear();\n            }\n            if (logFiner) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"<ByteBufferPool> TAKE FROM POOL in poll(): buffer: \").append(Utils.buffToString(retBuff));\n                sb.append(\"; qSize: \").append(thePool.size()).append(\" allocSize: \").append(poolSize.get());\n                if (logFinest) {\n                    sb.append(\" Trace: \");\n                    logger.log(Level.INFO, sb.toString(), new Throwable());\n                } else {\n                    logger.log(Level.INFO, sb.toString());\n                }\n            }\n\n            if (trackAllocations && retBuff != null) {\n                if (!checkBuffer(retBuff, false, true)) {\n                    logger.log(Level.WARNING, \" \\n\\n  <ByteBufferPool> trackAllocations ASSERTION FAILURE. retBuf = \" + Utils.buffToString(retBuff)\n                            + \"; TAKE FROM POOL! expect: false update: true\", new Exception(\"ASSERTION_FAILURE\"));\n                }\n            }\n\n        }\n\n    }\n\n    public ByteBuffer poll(long timeout, TimeUnit unit) throws InterruptedException {\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        final boolean logFiner = logFinest || logger.isLoggable(Level.FINER);\n\n        ByteBuffer retBuff = thePool.poll();\n\n        try {\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = tryAllocateBuffer();\n\n            if (retBuff != null) {\n                return retBuff;\n            }\n\n            retBuff = thePool.poll(timeout, unit);\n\n            return retBuff;\n        } finally {\n            if (retBuff != null) {\n                retBuff.clear();\n            }\n            if (logFiner) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"<ByteBufferPool> TAKE FROM POOL: buffer: \").append(Utils.buffToString(retBuff));\n                sb.append(\"; qSize: \").append(thePool.size()).append(\" allocSize: \").append(poolSize.get());\n                if (logFinest) {\n                    sb.append(\" Trace: \");\n                    logger.log(Level.INFO, sb.toString(), new Throwable());\n                } else {\n                    logger.log(Level.INFO, sb.toString());\n                }\n            }\n\n            if (trackAllocations && retBuff != null) {\n                if (!checkBuffer(retBuff, false, true)) {\n                    logger.log(Level.WARNING, \" \\n\\n  <ByteBufferPool> trackAllocations ASSERTION FAILURE. retBuf = \" + Utils.buffToString(retBuff)\n                            + \"; TAKE FROM POOL! expect: false update: true\", new Exception(\"ASSERTION_FAILURE\"));\n                }\n            }\n        }\n    }\n\n    public boolean put(ByteBuffer buff) {\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        final boolean logFiner = logFinest || logger.isLoggable(Level.FINER);\n\n        if (logFiner) {\n            StringBuilder sb = new StringBuilder();\n            sb.append(\"<ByteBufferPool> PUT BACK TO POOL: buffer: \").append(Utils.buffToString(buff));\n            sb.append(\"; qSize: \").append(thePool.size()).append(\" allocSize: \").append(poolSize.get());\n            if (logFinest) {\n                sb.append(\" Trace: \");\n                logger.log(Level.INFO, sb.toString(), new Throwable());\n            } else {\n                logger.log(Level.INFO, sb.toString());\n            }\n        }\n\n        if (buff == null) {\n            return false;\n        }\n\n        if (trackAllocations) {\n            if (!checkBuffer(buff, true, false)) {\n                logger.log(Level.WARNING, \" \\n\\n  <ByteBufferPool> trackAllocations ASSERTION FAILURE. retBuf = \" + Utils.buffToString(buff)\n                        + \"; RETURN TO POOL! expect: true update: false\", new Exception(\"ASSERTION_FAILURE\"));\n                return false;\n            }\n        }\n\n        // test and clear the interrupted flag\n        for (; ; ) {\n            final boolean isInterrupted = Thread.interrupted();\n            try {\n                final boolean returned = thePool.offer(buff);\n                if (returned) {\n                    return true;\n                }\n            } finally {\n                if (isInterrupted) {\n                    Thread.currentThread().interrupt();\n                }\n            }\n        }\n    }\n\n    public int getBufferSize() {\n        return bufferSize;\n    }\n\n    public int getSize() {\n        return thePool.size();\n    }\n\n    public String identityMapStats() {\n        StringBuilder sb = new StringBuilder();\n        synchronized (mapTrack) {\n            for (Map.Entry<ByteBuffer, AtomicBoolean> entry : mapTrack.entrySet()) {\n                sb.append(\"\\n\").append(Utils.buffToString(entry.getKey())).append(\" -> inUse: \").append(entry.getValue().get());\n            }\n        }\n        return sb.toString();\n    }\n\n    public int getCapacity() {\n        return poolSize.get();\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/AbstractFDTCloseable.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Convenient class which implements FDTCloseable. It uses also a thread to\n * notify the {@link internalClose} for all classes which extended this class\n *\n * @author ramiro\n */\npublic abstract class AbstractFDTCloseable implements FDTCloseable {\n\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(AbstractFDTCloseable.class.getName());\n    //helper thread used to notify internalClose in an async way\n    private static final AsynchronousCloseThread closer;\n\n    static {\n        AsynchronousCloseThread tmp = null;\n        try {\n            tmp = new AsynchronousCloseThread();\n            tmp.start();\n        } catch (Throwable t) {\n            //If smth fails here ... FDT cannot continue\n            //The only case can be if the class cannot be loaded or OOM is thrown ...\n            System.err.println(\"\\n\\n Cannot instantiate AsynchronousCloseThread !! \\n\\n\");\n            t.printStackTrace();\n            throw new RuntimeException(\"Cannot instantiate AsynchronousCloseThread\", t);\n        }\n\n        closer = tmp;\n    }\n\n    /**\n     * The lock can be used by subclasses to synchronize the access to\n     * <code>closed</code> field\n     * <p>\n     * internalClose is called with this lock taken\n     */\n    protected final Object closeLock = new Object();\n    protected volatile boolean closed;\n    private volatile String downMessage;\n    private volatile Throwable downCause;\n\n    //TODO - It is safe, but it is deadlock proned\n    // Probably this the classes must be instantiated only once;\n    // and once closed they should not be allowed to use the same stream again\n    public AbstractFDTCloseable() {\n        closed = false;\n    }\n\n    public boolean close(final String downMessage, final Throwable downCause) {\n\n        synchronized (closeLock) {\n            if (!isClosed()) {\n\n                setClosed(true);\n\n                this.downMessage = downMessage;\n                this.downCause = downCause;\n\n                //async close\n                closer.workingQueue.add(this);\n\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public boolean isClosed() {\n        return closed;\n    }\n\n    public void setClosed(boolean closed) {\n        this.closed = closed;\n    }\n\n    public String downMessage() {\n        return downMessage;\n    }\n\n    public Throwable downCause() {\n        return downCause;\n    }\n\n    /**\n     * this must be implemented , it is called only once even if close(*) is called multiple times\n     * this is called with closeLock taken\n     */\n    protected abstract void internalClose() throws Exception;\n\n    /**\n     * Helper thread to perform all internalClose notifications in an asynchronous fashion\n     * It should respect the \"trace\" of the close inside the FDT app\n     *\n     * @author ramiro\n     */\n    private static final class AsynchronousCloseThread extends Thread {\n\n        BlockingQueue<AbstractFDTCloseable> workingQueue;\n\n        private AsynchronousCloseThread() {\n            workingQueue = new LinkedBlockingQueue<>();\n            this.setDaemon(true);\n            this.setName(\" AsyncCloseThread [ \" + workingQueue.size() + \" ]\");\n        }\n\n        public void run() {\n            AbstractFDTCloseable closeable = null;\n\n            for (; ; ) {\n                try {\n                    this.setName(\" AsyncCloseThread waiting to take wqSize: \" + workingQueue.size());\n\n                    closeable = null;\n                    closeable = workingQueue.take();\n\n                    this.setName(\" AsyncCloseThread CLOSING [ \" + closeable + \" ] wqSize: \" + workingQueue.size());\n\n                    //internalClose() MUST be called with closeLock taken!\n                    synchronized (closeable.closeLock) {\n                        closeable.internalClose();\n                    }\n\n                } catch (InterruptedException ie) {\n                    logger.log(Level.WARNING, \"[ AsynchronousCloseThread ] [ HANDLED ] Got InterruptedException on task [ \" + closeable + \" ] Exc:\", ie);\n                    Thread.interrupted();\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"[ AsynchronousCloseThread ] [ HANDLED ] Got generic exception on task [ \" + closeable + \" ] Exc:\", t);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/AbstractFDTIOEntity.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport lia.util.net.copy.Accountable;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Abstract class for all other classes inside FDT which may be {@link Accountable}\n * and {@link FDTCloseable}in the same time\n *\n * @author ramiro\n */\npublic abstract class AbstractFDTIOEntity extends AbstractFDTCloseable implements Accountable {\n\n    private final AtomicLong totalProcessedBytes;\n    private final AtomicLong totalUtilBytes;\n\n    public AbstractFDTIOEntity(long initialProcessedBytes, long initialUtilBytes) {\n        totalProcessedBytes = new AtomicLong(initialProcessedBytes);\n        totalUtilBytes = new AtomicLong(initialUtilBytes);\n    }\n\n    public AbstractFDTIOEntity() {\n        this(0, 0);\n    }\n\n    public long addAndGetTotalBytes(long delta) {\n        return totalProcessedBytes.addAndGet(delta);\n    }\n\n    public long addAndGetUtilBytes(long delta) {\n        return totalUtilBytes.addAndGet(delta);\n    }\n\n    public long getTotalBytes() {\n        return totalProcessedBytes.get();\n    }\n\n    public long getUtilBytes() {\n        return totalUtilBytes.get();\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/AcceptableTask.java",
    "content": "package lia.util.net.common;\n\nimport lia.util.net.copy.FDTServer;\nimport lia.util.net.copy.FDTSessionManager;\nimport lia.util.net.copy.transport.ControlChannel;\nimport lia.util.net.copy.transport.gui.ServerSessionManager;\n\nimport java.io.IOException;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.UUID;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Raimondas Sirvinskas\n * @version 1.0\n */\npublic final class AcceptableTask implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(AcceptableTask.class.getName());\n\n    private static final Config config = Config.getInstance();\n\n    private static final FDTSessionManager fdtSessionManager = FDTSessionManager.getInstance();\n\n    final SocketChannel sc;\n\n    final Socket s;\n\n    public AcceptableTask(final SocketChannel sc) throws IOException {\n\n        if (sc == null) {\n            throw new NullPointerException(\"SocketChannel cannot be null in AcceptableTask\");\n        }\n\n        if (sc.socket() == null) {\n            throw new NullPointerException(\"Null Socket for SocketChannel in AcceptableTask\");\n        }\n\n        this.sc = sc;\n        this.s = sc.socket();\n        this.s.setTcpNoDelay(true);\n    }\n\n    public void run() {\n\n        if (!FDTServer.filterSourceAddress(s))\n            return;\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \" AcceptableTask for \" + sc + \" STARTED!\");\n        }\n        final String sdpConfFlag = System.getProperty(\"com.sun.sdp.conf\");\n        final boolean bSDP = (sdpConfFlag != null && !sdpConfFlag.isEmpty());\n        if (!bSDP) {\n            try {\n                s.setKeepAlive(true);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Cannot set KEEP_ALIVE for \" + sc\n                        + \". Will ignore the error. Contact your sys admin.\", t);\n            }\n\n            try {\n                // IPTOS_LOWCOST (0x02) IPTOS_RELIABILITY (0x04) IPTOS_THROUGHPUT (0x08) IPTOS_LOWDELAY (0x10)\n                s.setTrafficClass(0x04 | 0x08 | 0x010);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING,\n                        \"[ FDTServer ] [ AcceptableTask ] Cannot set traffic class for \"\n                                + sc\n                                + \"[ IPTOS_RELIABILITY (0x04) | IPTOS_THROUGHPUT (0x08) | IPTOS_LOWDELAY (0x10) ] Will ignore the error. Contact your sys admin.\",\n                        t);\n            }\n        }\n\n        final ByteBuffer firstByte = ByteBuffer.allocate(1);\n        final ByteBuffer clientIDBuff = ByteBuffer.allocate(16);\n\n        Selector tmpSelector = null;\n        SelectionKey sk = null;\n\n        configureSocket(firstByte, clientIDBuff, tmpSelector, sk);\n    }\n\n    private void configureSocket(ByteBuffer firstByte, ByteBuffer clientIDBuff, Selector tmpSelector, SelectionKey sk) {\n        UUID clientSessionID;\n        try {\n\n            int count = -1;\n            while (firstByte.hasRemaining()) {\n                count = sc.read(firstByte);\n                if (count < 0) {\n                    logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Unable to read header for socket [ \" + s\n                            + \" ] The stream will be closed.\");\n                    try {\n                        sc.close();\n                    } catch (Throwable ignored) {\n                        // ignore\n                    }\n                    return;\n                }\n\n                if (firstByte.hasRemaining()) {\n                    tmpSelector = Selector.open();\n                    sk = sc.register(tmpSelector, SelectionKey.OP_READ);\n                    tmpSelector.select();\n                }\n            }\n\n            if (sk != null) {\n                sk.cancel();\n                sk = null;\n            }\n\n            firstByte.flip();\n            final byte firstB = firstByte.get();\n\n            switch (firstB) {\n\n                // Control channel\n                case 0: {\n                    if (config.isGSIModeEnabled() || config.isGSISSHModeEnabled()) {\n                        logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Got a remote control channel [ \" + s\n                                + \" ] but in GSI mode ... will be rejected.\");\n                        try {\n                            byte[] key = {0};\n                            sc.write(ByteBuffer.wrap(key));\n                            sc.close();\n                        } catch (Throwable ignored) {\n                            // ignore\n                        }\n                        return;\n                    }\n\n                    sc.configureBlocking(true);\n                    ControlChannel ct = null;\n\n                    try {\n                        ct = new ControlChannel(s, fdtSessionManager);\n                        // fdtSessionID = ct.fdtSessionID();\n                        fdtSessionManager.addFDTClientSession(ct);\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Cannot instantiate ControlChannel\", t);\n                        ct = null;\n                    }\n\n                    if (ct != null) {\n                        new Thread(ct, \"ControlChannel thread for [ \" + s.getInetAddress() + \":\" + s.getPort() + \" ]\").start();\n                    }\n                    break;\n                }\n\n                // Worker channel\n                case 1: {\n                    if (config.isBlocking()) {\n                        sc.configureBlocking(true);\n                    } else {\n                        sc.configureBlocking(false);\n                    }\n\n                    while (clientIDBuff.hasRemaining()) {\n                        count = sc.read(clientIDBuff);\n                        if (count < 0) {\n                            logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Unable to read clientID. The stream will be closed\");\n                            Utils.closeIgnoringExceptions(sc);\n                            return;\n                        }\n\n                        if (clientIDBuff.hasRemaining()) {\n                            // THIS CANNOT?!? happen in blocking mode ( JVM should throw exception if this happens\n                            // ... but )\n                            if (config.isBlocking()) {\n                                logger.log(Level.WARNING,\n                                        \"[ FDTServer ] [ AcceptableTask ] Blocking mode ... unable to read clientID. The stream will be closed\");\n                                Utils.closeIgnoringExceptions(sc);\n                                return;\n                            }\n                        } else {\n                            // everything has been read\n                            break;\n                        }\n\n                        if (tmpSelector == null) {\n                            tmpSelector = Selector.open();\n                        }\n\n                        if (!config.isBlocking()) {\n                            sk = sc.register(tmpSelector, SelectionKey.OP_READ);\n                            tmpSelector.select();\n                        }\n                    }// while\n\n                    if (sk != null) {\n                        sk.cancel();\n                    }\n\n                    clientIDBuff.flip();\n                    clientSessionID = new UUID(clientIDBuff.getLong(), clientIDBuff.getLong());\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \"[ FDTServer ] [ AcceptableTask ] New socket from clientID: \" + clientSessionID);\n                    }\n\n                    fdtSessionManager.addWorker(clientSessionID, sc);\n                    break;\n                }\n\n                // Ping channel - RTT\n                case 2: {\n                    break;\n                }\n\n                // GUI special (sounds special, doesn't it) channel\n                case 3: {\n                    sc.configureBlocking(true);\n                    ServerSessionManager sm = null;\n                    try {\n                        sm = new ServerSessionManager(s);\n                        new Thread(sm, \"GUIControlChannel thread for [ \" + s.getInetAddress() + \":\" + s.getPort() + \" ]\").start();\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Cannot instantiate GUI ControlChannel\", t);\n                    }\n                    break;\n                }\n\n                default: {\n                    logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Unable to understand initial cookie: \" + firstB);\n                    Utils.closeIgnoringExceptions(s);\n                    return;\n                }\n            }\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Exception: \", t);\n            Utils.closeIgnoringExceptions(sc);\n        } finally {\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \" AcceptableTask for \" + s + \" FINISHED!\");\n            }\n            Utils.closeIgnoringExceptions(tmpSelector);\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/Config.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport lia.util.net.copy.FDTMain;\nimport lia.util.net.copy.PosixFSFileChannelProviderFactory;\nimport org.opentsdb.client.HttpClientImpl;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.net.*;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport java.util.regex.Pattern;\n\n/**\n * Configuration params for FDT\n *\n * @author ramiro\n * @author Lucian Musat\n */\npublic class Config {\n\n    // The size of the buffer which is sent over the wire!\n    // TODO make this a parameter\n    public static final int NETWORK_BUFF_LEN_SIZE;\n    // public static final String SINGLE_CMDLINE_ARGS[] = { \"-S\", \"-pull\", \"-N\", \"-gsi\", \"-bio\", \"-r\", \"-fbs\", \"-ll\",\n    // \"-loop\", \"-enableLisaRestart\", \"-md5\", \"-printStats\", \"-gsissh\", \"-noupdates\", \"-silent\"};\n    public static final String[] SINGLE_CMDLINE_ARGS = {\"-v\", \"-vv\", \"-vvv\", \"-loop\", \"-r\", \"-pull\", \"-printStats\",\n            \"-N\", \"-bio\", \"-gsi\", \"-gsissh\", \"-notmp\", \"-nolock\", \"-nolocks\", \"-nettest\", \"-genb\", \"-autoport\", \"-stable\"};\n    public static final String[] VALUE_CMDLINE_ARGS = {\"-bs\", \"-P\", \"-ss\", \"-limit\", \"-preFilters\", \"-postFilters\",\n            \"-monID\", \"-ms\", \"-c\", \"-p\", \"-sshp\", \"-gsip\", \"-iof\", \"-sn\", \"-rCount\", \"-wCount\", \"-pCount\", \"-d\",\n            \"-writeMode\", \"-lisa_rep_delay\", \"-apmon_rep_delay\", \"-fl\", \"-reportDelay\", \"-ka\", \"-tp\", \"-shell\"};\n    public static final String POSSIBLE_VALUE_CMDLINE_ARGS[] = {\"-enable_apmon\", \"-lisafdtclient\", \"-lisafdtserver\",\n            \"-f\", \"-F\", \"-h\", \"-H\", \"--help\", \"-help,\" + \"-u\", \"-U\", \"--update\", \"-update\"};\n    /**\n     * used in conjuction with -fl to delimit the eventual destination file name\n     * e.g. {@code /orginal/file/name / /destination/file/name}\n     */\n    public static final String REGEX_REMAP_DELIMITER = \"(\\\\s)+/(\\\\s)+\";\n    // all of this are set by the ant script\n    public static final String FDT_MAJOR_VERSION = \"0\";\n    public static final String FDT_MINOR_VERSION = \"27\";\n    public static final String FDT_MAINTENANCE_VERSION = \"0\";\n    public static final String FDT_FULL_VERSION = FDT_MAJOR_VERSION + \".\" + FDT_MINOR_VERSION + \".\"\n            + FDT_MAINTENANCE_VERSION;\n    public static final String FDT_RELEASE_DATE = \"2024-11-11\";\n    public static final String FDT_RELEASE_TIME = \"2030\";\n    // the size of header packet sent over the wire -\n    // TODO - this should be dynamic ... or not ( performance resons ?! )\n    public static final int HEADER_SIZE = 56;\n    public static final int HEADER_SIZE_v2 = 56;\n    public static final boolean TRACK_ALLOCATIONS = true;\n    public static final int KILO = 1024;\n    // 1 MByte\n    public static final int DEFAULT_BUFFER_SIZE = KILO * KILO; // 1MB\n    // this should be used for syncronizations at application level ()\n    public static final Object BIG_FDTAPP_LOCK = new Object();\n    // default is 4\n    public static final int DEFAULT_SOCKET_NO = 4;\n    public static final int DEFAULT_PORT_NO = 54321;\n    public static final int DEFAULT_TRANSFER_PORT_NO = 43210;\n    public static final long DEFAULT_KEEP_ALIVE_NANOS = TimeUnit.MINUTES.toNanos(2);\n    public static final int DEFAULT_PORT_NO_GSI = 54320;\n    public static final int DEFAULT_PORT_NO_SSH = 22;\n    public static final String DEFAULT_SHELL = \"/bin/bash\";\t\n\t\n    /**\n     * Check if remote server is needed. We use SSH channels to control remote startup. <br>\n     * In SSH/SCP mode we have three types of syntax we need to support:\n     * <ul>\n     * <li>fdt /local/path [user]@remotehost:/remote/path : <br>\n     * In this case a remote server si started on remote host and client starts in \"PUSH\" mode The server accept\n     * connection just from the the given client and exits when the transfer finishes\n     * <li>fdt /local/path [user]@remotehost:/remote/path : <br>\n     * In this case a remote server si started on remote host and client starts in \"PULL\" mode The server accept\n     * connection just from the the given client and exits when the transfer finishes\n     * <li>fdt [user]@remotehost1:/remote/path1 [user]@remotehost2:/remote/path2 : <br>\n     * In this case both the server and the client are started remotely (the local fdt acts as an agent for the transfer\n     * </ul>\n     */\n    // different client/server configuration set using SSH\n    public static final int SSH_NO_REMOTE = -1;\n    // REMOTE server, local client in push mode\n    public static final int SSH_REMOTE_SERVER_LOCAL_CLIENT_PUSH = 1;\n    // REMOTE server, local client in pull mode\n    public static final int SSH_REMOTE_SERVER_LOCAL_CLIENT_PULL = 2;\n    // REMOTE server, REMOTE client in push mode)\n    public static final int SSH_REMOTE_SERVER_REMOTE_CLIENT_PUSH = 3;\n\n    public static final String APMON=\"APMON\";\n    public static final String OPENTSDB=\"OPENTSDB\";\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(\"lia.util.net.common.Config\");\n    // env props which will be sent to remote peer\n    private final static String[] exportedSysProps = {\"user.name\", \"user.home\", \"user.dir\", \"file.separator\",\n            \"file.encoding\", \"path.separator\"};\n    private volatile static Config _thisInstance;\n\n    static {\n        int defaultMSSSize;\n        int minMTU;\n        try {\n            minMTU = getMinMTU();\n            defaultMSSSize = minMTU - 40;\n        } catch (Throwable ignore) {\n            defaultMSSSize = 1460;\n        }\n\n        if (defaultMSSSize < 1000) {\n            defaultMSSSize = 1460;\n        }\n\n        NETWORK_BUFF_LEN_SIZE = defaultMSSSize;\n    }\n\n    // default will be false\n    private final boolean isNagleEnabled;\n    private final boolean isStandAlone;\n    private final String sshKeyPath;\n    private String apMonHosts;\n    private final boolean isLisaRestartEnabled;\n    private final String writeMode;\n    private final String preFilters;\n    private final String postFilters;\n    private final String monID;\n    private final boolean isNetTest;\n    private final boolean isGenTest;\n    private final long keepAliveDelayNanos;\n    private final FileChannelProviderFactory fileChannelProviderFactory;\n    private int byteBufferSize = DEFAULT_BUFFER_SIZE;\n    // shall I get the data from server? - used only by the client\n    private boolean isPullMode = false;\n    private boolean isCoordinatorMode;\n    private boolean isRetrievingLogFile;\n    private boolean isThirdPartyCopyAgent;\n    private int sockNum = DEFAULT_SOCKET_NO;\n    private int sockBufSize = -1;\n    private long rateLimit = -1;\n    private long rateLimitDelayMillis = 300L;\n    private int readersCount = 1;\n    private int writersCount = 1;\n    private int maxPartitionsCount = 100;\n    private String hostname;\n    private String lisaHost;\n    private int lisaPort;\n    private int portNo;\n    private int portNoGSI;\n    private int portNoSSH;\n    private int destPort;\n    private int remoteTransferPort;\n    private ArrayBlockingQueue<Integer> transportPorts;\n    private final List<Object> tp;\n    private String[] fileList;\n    private String[] remappedFileList;\n    private String destDir;\n    private String listFilesFrom;\n    private String sIP;\n    private String dIP;\n    private String opentsdb = null;\n    private String opentsdbProtocol = System.getProperty(\"opentsdb.protocol\", org.apache.http.HttpHost.DEFAULT_SCHEME_NAME+ \"://\");\n    private boolean bComputeMD5 = false;\n    private boolean bRecursive = false;\n    private boolean bCheckUpdate = false;\n    private boolean isBlocking = false;\n    private boolean bUseFixedBlocks = false;\n    private boolean bLocalLoop = false;\n    private boolean bLoop = false;\n    private NetMatcher sourceAddressFilter = null;\n    private int IORetryFactor = 2;\n    private int selectorsNo = 1;\n    private boolean bDisableLisa = false;\n    private long lisaReportInterval = 20;\n    private long apMonReportInterval = 20;\n    // for client side in SSH mode\n    private boolean bSSHMode = false;\n    private boolean autoPort = false;\n    private int portRange = 100;\n    private boolean bGSISSHMode = false;\n    private boolean bGSIMode = false;\n    private String[] aSourceUsers = null;\n    private String[] aSourceHosts = null;\n    private String sDestinationUser = null;\n    private String sLocalAddresses = null;\n    private String sStartServerCommand = null;\n    private String logLevel;\n    private String massStorageConfig = null;\n    private String massStorageType = null;\n    private MassStorage storageParams = null;\n    private Level statsLevel = null;\n    private Map<String, Object> configMap;\n    private boolean isNoTmpFlagSet = false;\n    private boolean isNoLockFlagSet = false;\n    private long consoleReportingTaskDelay = 5;\n    private Map<String, Integer> sessionPortMap = new HashMap<>();\n    private Map<Integer, List<Object>> sessionSocketMap = new HashMap<>();\n    private HttpClientImpl httpClient = null;\n    private String customShell = null;\n\t\n    /**\n     * @param configMap\n     * @throws InvalidFDTParameterException if incorrect values are supplied for parameters\n     */\n    private Config(final Map<String, Object> configMap) throws InvalidFDTParameterException {\n        this.configMap = configMap;\n        if (configMap == null) {\n            throw new InvalidFDTParameterException(\"Null config map\");\n        }\n\n        for (String exportedSysProp : exportedSysProps) {\n            configMap.put(exportedSysProp, System.getProperty(exportedSysProp));\n        }\n\n        isStandAlone = (configMap.get(\"-S\") == null);\n        setRetrievingLogFile(configMap.get(\"-sID\"));\n        byteBufferSize = Utils.getIntValue(configMap, \"-bs\", DEFAULT_BUFFER_SIZE);\n        configMap.put(\"-bs\", String.valueOf(byteBufferSize));\n\n        sockNum = Utils.getIntValue(configMap, \"-P\", DEFAULT_SOCKET_NO);\n        configMap.put(\"-P\", String.valueOf(sockNum));\n\n        sockBufSize = Utils.getIntValue(configMap, \"-ss\", -1);\n        configMap.put(\"-ss\", String.valueOf(sockBufSize));\n\n        rateLimit = Utils.getLongValue(configMap, \"-limit\", -1);\n        if ((rateLimit > 0) && (rateLimit < NETWORK_BUFF_LEN_SIZE)) {\n            rateLimit = NETWORK_BUFF_LEN_SIZE;\n            logger.log(Level.INFO, \" The rate limit (-limit) is too small. It will be set to \" + rateLimit\n                    + \" Bytes/s\");\n        }\n        configMap.put(\"-limit\", String.valueOf(rateLimit));\n        rateLimitDelayMillis = Utils.getLongValue(configMap, \"-limitDelay\", 300L);\n        configMap.put(\"-limitDelay\", String.valueOf(rateLimitDelayMillis));\n\n        preFilters = Utils.getStringValue(configMap, \"-preFilters\", null);\n        postFilters = Utils.getStringValue(configMap, \"-postFilters\", null);\n        monID = Utils.getStringValue(configMap, \"-monID\", null);\n\n        this.massStorageConfig = Utils.getStringValue(configMap, \"-ms\", null);\n        this.massStorageType = Utils.getStringValue(configMap, \"-mst\", null);\n\n        this.opentsdb = Utils.getStringValue(configMap, \"-opentsdb\", \"localhost:4242\");\n\n        try {\n            if ((massStorageType() != null) && massStorageType().equals(\"dcache\")) {\n                System.setProperty(\"lia.util.net.common.FileChannelProviderFactory\",\n                        \"edu.caltech.hep.dcapj.dCacheFileChannelProviderFactory\");\n            }\n        } catch (Throwable e) {\n            System.err.println(\"FDT was unable to set the FileChannelProviderFactory env variable\");\n            e.printStackTrace();\n            System.out.flush();\n            System.err.flush();\n            System.exit(2502);\n        }\n\n        final String className = System.getProperty(\"lia.util.net.common.FileChannelProviderFactory\");\n        FileChannelProviderFactory tmpFCPF = null;\n\n        if (className != null) {\n            logger.log(Level.INFO, \"Trying to load user defined FileChannelProviderFactory: \" + className);\n            try {\n                final Class<?> c = Class.forName(className, true, ClassLoader.getSystemClassLoader());\n                tmpFCPF = (FileChannelProviderFactory) c.newInstance();\n            } catch (Throwable t) {\n                throw new InvalidFDTParameterException(\"Unable to load the FileChannelProviderFactory\", t);\n            }\n        } else {\n            tmpFCPF = new PosixFSFileChannelProviderFactory();\n        }\n\n        this.fileChannelProviderFactory = tmpFCPF;\n\n        // should not get here\n        if (this.fileChannelProviderFactory == null) {\n            throw new InvalidFDTParameterException(\"The FileChannelProviderFactory cannot be null!\");\n        }\n\n        logger.log(Level.INFO, \"Using \" + this.fileChannelProviderFactory.getClass().getName()\n                + \" as FileChannelProviderFactory\");\n\n        hostname = Utils.getStringValue(configMap, \"-c\", null);\n\n        if ((hostname != null) && (hostname.length() == 0)) {\n            hostname = null;\n        } else {\n            isPullMode = (configMap.get(\"-pull\") != null) || (configMap.get(\"-sID\") != null);\n            if (isPullMode) {\n                configMap.put(\"-pull\", \"\");\n            }\n        }\n\n        autoPort = configMap.get(\"-autoport\") != null;\n        if (autoPort) {\n            portRange = Utils.getIntValue(configMap, \"-portRange\", 100);\n        }\n\n        final long ka = Utils.getLongValue(configMap, \"-ka\", TimeUnit.NANOSECONDS.toSeconds(DEFAULT_KEEP_ALIVE_NANOS));\n        this.keepAliveDelayNanos = (ka < 0) ? DEFAULT_KEEP_ALIVE_NANOS : TimeUnit.SECONDS.toNanos(ka);\n        configMap.put(\"-ka\", String.valueOf(TimeUnit.NANOSECONDS.toSeconds(this.keepAliveDelayNanos)));\n\n        portNo = Utils.getIntValue(configMap, \"-p\", DEFAULT_PORT_NO);\n        transportPorts = Utils.getTransportPortsValue(configMap, \"-tp\", DEFAULT_TRANSFER_PORT_NO);\n        if(transportPorts.size() == 1 && transportPorts.element().intValue() == DEFAULT_TRANSFER_PORT_NO)\n        \ttransportPorts.clear();\n        tp = Arrays.asList(transportPorts.toArray());\n        isCoordinatorMode = (configMap.get(\"-coord\") != null);\n        isThirdPartyCopyAgent = (configMap.get(\"-agent\") != null);\n\n        portNoGSI = Utils.getIntValue(configMap, \"-gsip\", DEFAULT_PORT_NO_GSI);\n        portNoSSH = Utils.getIntValue(configMap, \"-sshp\", DEFAULT_PORT_NO_SSH);\n        IORetryFactor = Utils.getIntValue(configMap, \"-iof\", 1);\n        int avP = Runtime.getRuntime().availableProcessors();\n        if (avP < 1) {\n            avP = 1;\n        }\n        selectorsNo = Utils.getIntValue(configMap, \"-sn\", avP);\n        readersCount = Utils.getIntValue(configMap, \"-rCount\", 1);\n        writersCount = Utils.getIntValue(configMap, \"-wCount\", 1);\n        maxPartitionsCount = Utils.getIntValue(configMap, \"-pCount\", 100);\n\n        consoleReportingTaskDelay = Utils.getLongValue(configMap, \"-reportDelay\", 5);\n\n        isNagleEnabled = (configMap.get(\"-N\") != null);\n        isNetTest = (configMap.get(\"-nettest\") != null);\n        isGenTest = (configMap.get(\"-genb\") != null);\n        bGSIMode = (configMap.get(\"-gsi\") != null);\n        isBlocking = (configMap.get(\"-bio\") != null);\n        if (!isBlocking) {\n            isBlocking = (configMap.get(\"-nbio\") == null);\n        }\n\n        apMonHosts = Utils.getStringValue(configMap, \"-enable_apmon\", null);\n        bRecursive = (configMap.get(\"-r\") != null);\n        bUseFixedBlocks = (configMap.get(\"-fbs\") != null);\n        bLocalLoop = (configMap.get(\"-ll\") != null);\n        bLoop = (configMap.get(\"-loop\") != null);\n        isLisaRestartEnabled = (configMap.get(\"-enableLisaRestart\") != null);\n        bCheckUpdate = (configMap.get(\"-u\") != null);\n        destDir = Utils.getStringValue(configMap, \"-d\", null);\n        sIP = Utils.getStringValue(configMap, \"-sIP\", null);\n        dIP = Utils.getStringValue(configMap, \"-dIP\", null);\n        destPort = Utils.getIntValue(configMap, \"-dp\", -1);\n        remoteTransferPort = -1;\n        listFilesFrom = Utils.getStringValue(configMap, \"-ls\", null);\n        bComputeMD5 = (configMap.get(\"-md5\") != null);\n        sshKeyPath = Utils.getStringValue(configMap, \"-sshKey\", null);\n        customShell = Utils.getStringValue(configMap, \"-shell\", DEFAULT_SHELL);\n\t    \n        if (isNetTest) {\n            destDir = \"/dev/null\";\n            @SuppressWarnings(\"unchecked\")\n            List<String> lastParams = (List<String>) configMap.get(\"LastParams\");\n            lastParams.add(\"/dev/zero\");\n        }\n\n        if ((hostname != null) && (((destDir == null) || (destDir.length() == 0)) && listFilesFrom == null)) {\n            throw new IllegalArgumentException(\"No destination specified\");\n        }\n\n        // process local storage params\n        if (this.massStorageConfig != null) {\n            this.storageParams = new MassStorage();\n            if (!this.storageParams.init(massStorageConfig)) {\n                throw new IllegalArgumentException(\"Invalid mass storage configuration file\");\n            }\n        }\n\n        if (configMap.get(\"-printStats\") != null) {\n            statsLevel = Level.INFO;\n        }\n\n        isNoTmpFlagSet = (configMap.get(\"-notmp\") != null);\n        isNoLockFlagSet = ((configMap.get(\"-nolock\") != null) || (configMap.get(\"-nolocks\") != null));\n\n        writeMode = Utils.getStringValue(configMap, \"-writeMode\", null);\n\n        String sLisa = Utils.getStringValue(configMap, \"-lisafdtclient\", null);\n        if (sLisa == null) {\n            sLisa = Utils.getStringValue(configMap, \"-lisafdtserver\", null);\n\n            if (sLisa != null) {\n                sLisa = Utils.getStringValue(configMap, \"-lisafdtserver\", \"127.0.0.1:11001\");\n            }\n\n        } else {\n            sLisa = Utils.getStringValue(configMap, \"-lisafdtclient\", \"127.0.0.1:11001\");\n        }\n\n        if (sLisa == null) {\n            bDisableLisa = true;\n        }\n\n        lisaReportInterval = Utils.getIntValue(configMap, \"-lisa_rep_delay\", 20);\n        apMonReportInterval = Utils.getIntValue(configMap, \"-apmon_rep_delay\", 20);\n\n        lisaHost = null;\n        lisaPort = -1;\n\n        if (!bDisableLisa) {\n            try {\n                int idx = sLisa.indexOf(\":\");\n                if (idx > 0) {\n                    lisaHost = sLisa.substring(0, idx);\n                    lisaPort = Integer.parseInt(sLisa.substring(idx + 1));\n                } else if (idx == 0) {// only port\n                    lisaHost = \"127.0.0.1\";\n                    lisaPort = Integer.parseInt(sLisa.substring(1));\n                } else {\n                    lisaHost = sLisa;\n                    lisaPort = 11001;\n                }\n            } catch (Throwable t) {\n                if (lisaHost == null) {\n                    lisaHost = \"127.0.0.1\";\n                }\n                if (lisaPort == -1) {\n                    lisaPort = 11001;\n                }\n            }\n        }\n\n        /* start the server through SSH (just for client side)? */\n        if (/* configMap.get(\"-ssh\") != null || */configMap.get(\"SCPSyntaxUsed\") != null) {\n            // use GSI-SSH?\n            if (configMap.get(\"-gsissh\") != null) {\n                bGSISSHMode = true;\n            }\n            bSSHMode = true;\n            Object oSrc = configMap.get(\"sourceUsers\");\n            if (oSrc != null) {\n                String[] aSourceUsers = (String[]) oSrc;\n                if (aSourceUsers.length > 0) {\n                    this.aSourceUsers = aSourceUsers;\n                }\n            }\n            oSrc = configMap.get(\"sourceHosts\");\n            if (oSrc != null) {\n                String[] aSourceHosts = (String[]) oSrc;\n                if (aSourceHosts.length > 0) {\n                    this.aSourceHosts = aSourceHosts;\n                }\n            }\n            sDestinationUser = Utils.getStringValue(configMap, \"destinationUser\", System.getProperty(\"user.name\"));\n            // sDestinationUser = ( sDestinationUser==null?System.getProperty(\"user.name\"):sDestinationUser );\n            sLocalAddresses = Utils.getStringValue(configMap, \"-local\", null);\n            sStartServerCommand = Utils.getStringValue(configMap, \"-remote\", \"java -jar fdt.jar\");\n        }\n\n        if (configMap.containsKey(\"-f\") && !configMap.containsKey(\"-F\")) {\n            String sAllowedHosts = Utils.getStringValue(configMap, \"-f\", \"\");\n            if (sAllowedHosts.trim().length() == 0) {\n                // no hosts suplied, try to guess from the SSH_CLIENT env var\n                sAllowedHosts = System.getenv(\"SSH_CLIENT\");\n                if (sAllowedHosts != null) {\n                    sAllowedHosts = sAllowedHosts.split(\"(\\\\s)+\")[0];\n                }\n                // cannot continue, raise exception\n                if ((sAllowedHosts == null) || (sAllowedHosts.length() == 0)) {\n                    throw new InvalidFDTParameterException(\"source filter used but no host/ip supplied\");\n                }\n            }\n            sourceAddressFilter = new NetMatcher(sAllowedHosts.split(\":\"));\n        }\n\n        // try to get the fileList[]\n        @SuppressWarnings(\"unchecked\")\n        List<String> lastParams = (List<String>) configMap.get(\"LastParams\");\n        if ((lastParams == null) || lastParams.isEmpty()) {\n            String fList = Utils.getStringValue(configMap, \"-fl\", null);\n            if ((fList != null) && (fList.length() != 0)) {\n                //source files\n                List<String> arrayFileList = new ArrayList<String>();\n                //must accept null values\n                List<String> remappedArrayFileList = new ArrayList<String>();\n                BufferedReader br = null;\n                FileReader fr = null;\n                try {\n                    final Pattern splitPattern = Pattern.compile(REGEX_REMAP_DELIMITER);\n                    fr = new FileReader(fList);\n                    br = new BufferedReader(fr);\n                    String line = br.readLine();\n                    while (line != null) {\n                        final String[] tkns = splitPattern.split(line);\n                        final int tknsCount = tkns.length;\n                        if (tknsCount == 1) {\n                            arrayFileList.add(line);\n                            remappedArrayFileList.add(null);\n                        } else if (tknsCount == 2) {\n                            arrayFileList.add(tkns[0]);\n                            remappedArrayFileList.add(tkns[1]);\n                        } else {\n                            throw new IllegalArgumentException(\"The line=\" + line\n                                    + \", from -fl parameter cannot be parsed\");\n                        }\n                        line = br.readLine();\n                    }\n                    remappedFileList = remappedArrayFileList.toArray(new String[0]);\n                    fileList = arrayFileList.toArray(new String[0]);\n                } catch (Throwable t) {\n                    throw new IllegalArgumentException(\"Unable to decode file list\", t);\n                } finally {\n                    Utils.closeIgnoringExceptions(fr);\n                    Utils.closeIgnoringExceptions(br);\n                }\n            } else if (configMap.get(\"-sID\") != null) {\n                String sessionID = (String) configMap.get(\"-sID\");\n                String[] logFiles = getLogFiles(sessionID);\n                remappedFileList = logFiles;\n                fileList = logFiles;\n            }\n        } else {\n            configMap.remove(\"-fl\");\n            fileList = lastParams.toArray(new String[lastParams.size()]);\n            if ((fileList != null) && (fileList.length == 0)) {\n                fileList = null;\n            }\n        }\n        Object files = configMap.get(\"Files\");\n        if ((files != null) && (files instanceof String[]) && (((String[]) files).length > 0)) {\n            fileList = (String[]) files;\n        }\n\n        logger.log(Level.INFO, \"FDT started in {0} mode\", getFDTMode(configMap));\n        if (hostname != null) {// client mode\n            if (logger.isLoggable(Level.FINE)) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"Source file list --> remaped file list:\\n\");\n                final boolean bRemapFLNull = (remappedFileList == null);\n                for (int i = 0; (fileList != null) && (i < fileList.length); i++) {\n                    sb.append(fileList[i])\n                            .append(\" ---> \")\n                            .append((bRemapFLNull || (remappedFileList[i] == null)) ? \" default mapping: \"\n                                    + fileList[i] : \" remapped to: \" + remappedFileList[i]).append(\"\\n\");\n                }\n                logger.log(Level.FINE, sb.toString());\n                logger.log(Level.FINE, \"Remote destination directory: {0}\\nRemote host: {1} port: {2}\", new Object[]{\n                        destDir, hostname, portNo});\n            }\n        } else {// server mode\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.INFO, \"Local server will try to bind on port:{0}\", portNo);\n            }\n        }\n    }\n\n    public String getMonitor()\n    {\n        if(configMap.get(\"-opentsdb\") != null)\n        {\n            return OPENTSDB;\n        }\n        if (configMap.get(\"-apmon\") != null)\n        {\n            return APMON;\n        }\n       return APMON;\n    }\n\n    public void initOpenTSDBMonitorClient()\n    {\n        httpClient = new HttpClientImpl(opentsdbProtocol + getOpentsdb());\n    }\n\n    public String getFDTTag()\n    {\n        return Utils.getStringValue(configMap, \"-fdtTAG\", \"DEFAULT_FDT_TAG\");\n    }\n\n    public void setFDTTag(String fdtTag)\n    {\n        configMap.put(\"-fdtTAG\", fdtTag);\n    }\n\n\n    public HttpClientImpl getOpenTSDBMonitorClient()\n    {\n        return httpClient;\n    }\n\n    private static final int getMinMTU() {\n        int retMTU = 1500;\n\n        try {\n            final Enumeration<NetworkInterface> netInterfacesEnum = NetworkInterface.getNetworkInterfaces();\n            while (netInterfacesEnum.hasMoreElements()) {\n                final NetworkInterface netInteface = netInterfacesEnum.nextElement();\n\n                try {\n                    if (!netInteface.isUp()) {\n                        continue;\n                    }\n                } catch (NoSuchMethodError nsme) {\n                    // java < 1.6\n                    if (logger.isLoggable(Level.FINE)) {\n                        System.out.println(\"The current JVM is not able to determine if the net interface \"\n                                + netInteface + \"is up and running. JVM >= 1.6 should support this feature\");\n                    }\n                    return retMTU;\n                } catch (Throwable t) {\n                    System.err.println(\" Cannot determine if the interface: \" + netInteface + \" is up\");\n                    return retMTU;\n                }\n\n                int cMTU = -1;\n                try {\n                    cMTU = netInteface.getMTU();\n                } catch (SocketException se) {\n                    System.err.println(\" Cannot get MTU for netInterface: \" + netInteface + \" SocketException: \" + se);\n                } catch (NoSuchMethodError nsme) {\n                    if (logger.isLoggable(Level.FINE)) {\n                        System.out.println(\"The current JVM is not able to determine the MTU for the net interface \"\n                                + netInteface + \"is up and running. JVM >= 1.6 should support this feature\");\n                    }\n                    continue;\n                } catch (Throwable t) {\n                    // probably incompatible JVM version\n                    System.err.println(\" Cannot get MTU for netInterface: \" + netInteface + \" Exception: \" + t);\n                }\n\n                if ((cMTU < retMTU) && (cMTU > 0)) {\n                    retMTU = cMTU;\n                }\n            }// while\n        } catch (SocketException se) {\n            System.err.println(\" Cannot get min MTU for current instance of FDT. SocketException: \" + se);\n        } catch (Throwable t) {\n            System.err.println(\" Cannot get min MTU for current instance of FDT. Exception: \" + t);\n        }\n\n        return retMTU;\n    }\n\n    public static int getBulkSockConnect() {\n        return 30;\n    }\n\n    public static long getBulkSockConnectWait() {\n        return 1500;\n    }\n\n    public static final String getUsage() {\n        return Utils.getUsage();\n    }\n\n    public static int getMaxTakePollIter() {\n        return 1000;\n    }\n\n    public static final Config getInstance() {\n        synchronized (Config.class) {\n            while (_thisInstance == null) {\n                try {\n                    Config.class.wait();\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n        }\n\n        return _thisInstance;\n    }\n\n    public static final void initInstance(final Map<String, Object> configMap) throws Exception {\n\n        synchronized (Config.class) {\n            if (_thisInstance == null) {\n                _thisInstance = new Config(configMap);\n            }\n            Config.class.notifyAll();\n        }\n    }\n\n    private static void closeSessionRelatedSocks(List<Object> socks) {\n        if (socks != null) {\n            for (Object o : socks) {\n                if (o instanceof ServerSocketChannel) {\n                    try {\n                        ((ServerSocketChannel) o).close();\n                    } catch (IOException e) {\n                        logger.log(Level.WARNING, \"Failed to close ServerSocketChannel\", e);\n                    }\n                }\n                if (o instanceof ServerSocket) {\n                    try {\n                        ((ServerSocket) o).close();\n                    } catch (IOException e) {\n                        logger.log(Level.WARNING, \"Failed to close ServerSocket\", e);\n                    }\n                }\n                if (o instanceof SocketChannel) {\n                    try {\n                        ((SocketChannel) o).close();\n                    } catch (IOException e) {\n                        logger.log(Level.WARNING, \"Failed to close SocketChannel\", e);\n                    }\n                }\n                if (o instanceof Socket) {\n                    try {\n                        ((Socket) o).close();\n                    } catch (IOException e) {\n                        logger.log(Level.WARNING, \"Failed to close Socket\", e);\n                    }\n                }\n            }\n        }\n    }\n\n    private String[] getLogFiles(String sessionID) {\n    \treturn new String[] { System.getProperty(\"java.io.tmpdir\") + File.pathSeparatorChar + sessionID + \".log\" };\n    }\n\n    public String getListFilesFrom() {\n        return listFilesFrom;\n    }\n\n    public void setListFilesFrom(String listFilesFrom) {\n        this.listFilesFrom = listFilesFrom;\n    }\n\n    private String getFDTMode(Map<String, Object> configMap) {\n        if (configMap.get(\"-coord\") != null) {\n            return \"coordinator\";\n        } else if (configMap.get(\"-ls\") != null) {\n            return \"list files\";\n        } else if (configMap.get(\"-agent\") != null) {\n            return \"agent worker\";\n        }\n        return (hostname == null) && (configMap.get(\"SCPSyntaxUsed\") == null) ? \"server\" : \"client\";\n    }\n\n    public long getKeepAliveDelay(TimeUnit unit) {\n        return unit.convert(keepAliveDelayNanos, TimeUnit.NANOSECONDS);\n    }\n\n    public Map<String, Object> getConfigMap() {\n        return configMap;\n    }\n\n    public void setConfigMap(Map<String, Object> configMap) {\n        this.configMap = configMap;\n    }\n\n    public long getReportingTaskDelay() {\n        return consoleReportingTaskDelay;\n    }\n\n    public Level getStatsLevel() {\n        return statsLevel;\n    }\n\n    public String getMonID() {\n        return monID;\n    }\n\n    public int getRetryIOCount() {\n        return IORetryFactor;\n    }\n\n    public int getByteBufferSize() {\n        return byteBufferSize;\n    }\n\n    public boolean isNagleEnabled() {\n        return isNagleEnabled;\n    }\n\n    public boolean isGSIModeEnabled() {\n        return bGSIMode;\n    }\n\n    public int getSockNum() {\n        return sockNum;\n    }\n\n    public long getLisaReportingInterval() {\n        return lisaReportInterval;\n    }\n\n    public long getApMonReportingInterval() {\n        return apMonReportInterval;\n    }\n\n    /**\n     * @return the rate in Bytes/s\n     */\n    public long getRateLimit() {\n        return rateLimit;\n    }\n\n    public long getRateLimitDelay() {\n        return rateLimitDelayMillis;\n    }\n\n    public int getSockBufSize() {\n        return sockBufSize;\n    }\n\n    public String getLisaHost() {\n        return lisaHost;\n    }\n\n    public int getLisaPort() {\n        return lisaPort;\n    }\n\n    public void setLisaPort(int lisaPort) {\n        this.lisaPort = lisaPort;\n    }\n\n    public String getSshKeyPath() {\n        return sshKeyPath;\n    }\n\n    public boolean isNoTmpFlagSet() {\n        return isNoTmpFlagSet;\n    }\n\n    public boolean isNoLockFlagSet() {\n        return isNoLockFlagSet;\n    }\n\n    public String getHostName() {\n        if (configMap.get(\"-agent\") != null) {\n            return dIP;\n        }\n        return hostname;\n    }\n\n    public void setHostName(String hostname) {\n        this.configMap.put(\"-destinationHost\", hostname);\n        this.hostname = hostname;\n    }\n\n    public int getPort() {\n        return portNo;\n    }\n\n    public int getDefaultPort() {\n        return DEFAULT_PORT_NO;\n    }\n\n    public int getGSIPort() {\n        return portNoGSI;\n    }\n\n    public void setGSIPort(int port) {\n        this.portNoGSI = port;\n    }\n\n    public int getSSHPort() {\n        return portNoSSH;\n    }\n\n    public void setSSHPort(int port) {\n        this.portNoSSH = port;\n    }\n\n    public void setPortNo(int port) {\n        this.portNo = port;\n    }\n\n    public boolean isStandAlone() {\n        return isStandAlone;\n    }\n\n    public String getWriteMode() {\n        return writeMode;\n    }\n\n    public String[] getFileList() {\n        return fileList;\n    }\n\n    public void setFileList(String[] fileList) {\n        this.fileList = fileList;\n    }\n\n    public String[] getRemappedFileList() {\n        return remappedFileList;\n    }\n\n    public String getPreFilters() {\n        return preFilters;\n    }\n\n    public String getPostFilters() {\n        return postFilters;\n    }\n\n    public String getDestinationDir() {\n        return destDir;\n    }\n\n    public void setDestinationDir(String destDir) {\n        this.destDir = destDir;\n    }\n\n    public int getDestinationPort() {\n        return destPort;\n    }\n\n    public void setDestinationPort(int destPort) {\n        this.destPort = destPort;\n    }\n\n    public void registerTransferPortForSession(int newTransferPort, String sessionID) {\n        this.sessionPortMap.put(sessionID, newTransferPort);\n    }\n\n    public int getNewRemoteTransferPort() {\n    \tint rtp = -1;\n        try {\n            if (autoPort)\n            {\n                return getRandomPort(getDefaultPort());\n            }\n            if (!transportPorts.isEmpty()) {\n                rtp = this.transportPorts.poll(20, TimeUnit.SECONDS);\n                logger.log(Level.FINER,\"Reusing remote transfer port \" + rtp);\n            } else {\n            \trtp = findAvailablePort();\n            \tlogger.log(Level.FINER,\"Used new remote transfer port \" + rtp);\n            }\n            \n        } catch (Exception e) {\n            if (transportPorts.size() == 0) {\n                logger.log(Level.WARNING, \"No transfer ports defined or no free transfer ports left...\", e);\n            } else {\n                logger.log(Level.WARNING, \"Failed to retrieve remote transfer port\", e);\n            }\n        } \n        return rtp;\n    }\n    \n    private int getRandomPort(int defaultPort)\n    {\n        int randomPort = -1;\n        try {\n            Random r = new Random();\n            randomPort = r.nextInt(((defaultPort + portRange) - defaultPort) + 1) + defaultPort;\n            logger.log(Level.INFO, \"Auto FDT on port \" + randomPort);\n            new Thread(new Runnable() {\n                @Override\n                public void run() {\n                    new FDTMain();\n                }\n            }, \"FDT custom port \" + randomPort).start();\n        }\n        catch (Exception e)\n        {\n            logger.log(Level.INFO, \" FAILED auto FDT on port \" + randomPort);\n        }\n        return randomPort;\n    }\n\n    private int findAvailablePort() {\n\n    \t/**\n    \t * Returns a free port number on localhost.\n    \t * @since December 2017\n    \t * @author will\n    \t * @return a free port number on localhost\n    \t * @throws IllegalStateException if unable to find a free port\n    \t */\n    \t\ttry(ServerSocket socket = new ServerSocket(0)) {\n    \t\t\tsocket.setReuseAddress(true);\n    \t\t\treturn socket.getLocalPort();\n    \t\t} catch(IOException e)\n    \t\t{\n    \t\t\tlogger.log(Level.WARNING, \"Unable to find a free Socket\", e);\n    \t\t}\n    \t\t\n    \t\tthrow new IllegalStateException(\"Could not find a free TCP/IP port\");\n    }\n\n\tpublic void setSessionSocket(ServerSocketChannel ssc, ServerSocket ss, SocketChannel sc, Socket s, int port) {\n        List<Object> socks = new ArrayList<>();\n        socks.add(ssc);\n        socks.add(ss);\n        socks.add(sc);\n        socks.add(s);\n        sessionSocketMap.put(port, socks);\n    }\n\n    public void releaseRemoteTransferPort(String sessionID) {\n        if (sessionPortMap.keySet().contains(sessionID)) {\n            logger.log(Level.FINER, \"Trying to release transfer port from session \" + sessionID);\n            int sessionPort = sessionPortMap.get(sessionID);\n            if (sessionPort > 0) {\n                try {\n                    transportPorts.put(sessionPort);\n                    sessionPortMap.remove(sessionID);\n                    closeSessionRelatedSocks(sessionSocketMap.get(sessionPort));\n                } catch (InterruptedException e) {\n                    logger.log(Level.WARNING, \"Failed to release remote transfer port: \" + remoteTransferPort, e);\n                }\n            }\n        }\n    }\n\n    public int getRemoteTransferPort() {\n        return remoteTransferPort;\n    }\n\n    public List<Object> getRemoteTransferPorts() {\n        return tp;\n    }\n\n    public void setRemoteTransferPort(int remoteTransferPort) {\n        this.remoteTransferPort = remoteTransferPort;\n    }\n\n    public String getSourceIP() {\n        return sIP;\n    }\n\n    public String getDestinationIP() {\n        return dIP;\n    }\n\n    public void setDestinationIP(String dIP) {\n        this.dIP = dIP;\n    }\n\n    // TODO - As param ...\n    public int getNumberOfSelectors() {\n        return selectorsNo;\n    }\n\n    public String getApMonHosts() {\n        return apMonHosts;\n    }\n\n    public void setApMonHosts(String apMonHosts) {\n        this.apMonHosts = apMonHosts;\n    }\n\n    public boolean isCoordinatorMode() {\n        return isCoordinatorMode;\n    }\n\n    public void setCoordinatorMode(boolean coordinatorMode) {\n        this.isCoordinatorMode = coordinatorMode;\n        if (coordinatorMode) {\n            this.configMap.put(\"-coord\", true);\n        } else {\n            this.configMap.remove(\"-coord\");\n        }\n    }\n\n    public boolean isListFilesMode() {\n        return listFilesFrom != null && configMap.get(\"-ls\") != null;\n    }\n\n    public boolean isRetrievingLogFile() {\n        return isRetrievingLogFile || configMap.containsKey(\"-sID\");\n    }\n\n    public void setRetrievingLogFile(Object sessionID) {\n        this.isRetrievingLogFile = sessionID != null;\n        if (isRetrievingLogFile) {\n            this.configMap.put(\"-sID\", (String) sessionID);\n        } else {\n            this.configMap.remove(\"-sID\");\n        }\n    }\n\n    public boolean isPullMode() {\n        return isPullMode;\n    }\n\n    public void setPullMode(boolean pullMode) {\n        this.isPullMode = pullMode;\n        if (pullMode) {\n            this.configMap.put(\"-pull\", true);\n        } else {\n            this.configMap.remove(\"-pull\");\n        }\n    }\n\n    public boolean shouldUpdate() {\n        return bCheckUpdate;\n    }\n\n    public boolean isRecursive() {\n        return bRecursive;\n    }\n\n    public boolean isLisaDisabled() {\n        return bDisableLisa;\n    }\n\n    public boolean loop() {\n        return bLoop;\n    }\n\n    public boolean localLoop() {\n        return bLocalLoop;\n    }\n\n    public boolean useFixedBlocks() {\n        return bUseFixedBlocks;\n    }\n\n    public NetMatcher getSourceAddressFilter() {\n        return sourceAddressFilter;\n    }\n\n    public boolean computeMD5() {\n        return bComputeMD5;\n    }\n\n    public boolean isSSHModeEnabled() {\n        return bSSHMode;\n    }\n\n    public boolean isGSISSHModeEnabled() {\n        return bGSISSHMode;\n    }\n\n    public int getReadersCount() {\n        return readersCount;\n    }\n\n    public int getWritersCount() {\n        return writersCount;\n    }\n\n    public int getMaxPartitionCount() {\n        return maxPartitionsCount;\n    }\n\n    public int getSSHConfig() {\n\n        if (!bSSHMode) {\n            return SSH_NO_REMOTE;\n        }\n        final String sDestinationHost = Utils.getStringValue(configMap, \"destinationHost\", null);\n        if (((aSourceHosts == null) || (aSourceHosts.length == 0) || (aSourceHosts[0] == null))\n                && (sDestinationHost != null)) // /local/path [user]@remotehost:/remote/path\n        // the client is locally\n        {\n            return SSH_REMOTE_SERVER_LOCAL_CLIENT_PUSH;\n        }\n\n        if ((aSourceHosts != null) && (aSourceHosts.length > 0) && (sDestinationHost == null)) {\n            // [2] [user]@remotehost:/remote/path /local/path\n            return SSH_REMOTE_SERVER_LOCAL_CLIENT_PULL;\n        }\n\n        // [3] [user]@remotehost:/remote/path [user]@remotehost:/remote/path1\n        return SSH_REMOTE_SERVER_REMOTE_CLIENT_PUSH;\n\n    }\n\n    public boolean isBlocking() {\n        return isBlocking;\n    }\n\n    public String getDestinationUser() {\n        return sDestinationUser;\n    }\n\n    public boolean isLisaRestartEnabled() {\n        return isLisaRestartEnabled;\n    }\n\n    public String getLocalAddresses() {\n        return this.sLocalAddresses == null ? LocalHost.getStringPublicIPs4() : this.sLocalAddresses;\n    }\n\n    public String getRemoteCommand() {\n        return this.sStartServerCommand;\n    }\n\n    public String[] getSourceUsers() {\n        return this.aSourceUsers;\n    }\n\n    public String[] getSourceHosts() {\n        return this.aSourceHosts;\n    }\n\n    public String massStorageConfig() {\n        return this.massStorageConfig;\n    }\n\n    public String massStorageType() {\n        return this.massStorageType;\n    }\n\n    public MassStorage storageParams() {\n        return this.storageParams;\n    }\n\n    public boolean isNetTest() {\n        return isNetTest;\n    }\n\n    public boolean isGenTest() {\n        return isGenTest;\n    }\n\n    public String getLogLevel() {\n        return logLevel;\n    }\n\n    public void setLogLevel(String logLevel) {\n        this.logLevel = logLevel;\n    }\n\n    public FileChannelProviderFactory getFileChannelProviderFactory() {\n        return this.fileChannelProviderFactory;\n    }\n\n    public boolean isThirdPartyCopyAgent() {\n        return this.isThirdPartyCopyAgent;\n    }\n\n    public void setThirdPartyCopyAgent(boolean isThirdPartyCopyAgent) {\n        this.isThirdPartyCopyAgent = isThirdPartyCopyAgent;\n        if (isThirdPartyCopyAgent) {\n            this.configMap.put(\"-agent\", true);\n        } else {\n            this.configMap.remove(\"-agent\");\n        }\n    }\n\n    public String getListenAddress()\n    {\n        return (String)this.configMap.get(\"-FDT_LISTEN\");\n    }\n\n    public String getOpentsdb() {\n        return opentsdb;\n    }\n\n    public void setOpentsdb(String opentsdb) {\n        this.opentsdb = opentsdb;\n    }\n\n    public String getCustomShell() {\n        return customShell;\n    }\n\n    public boolean isThrottlingEnabled() {\n        return configMap.containsKey(\"-stable\");\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/ControlStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * @author Adrian Muraru\n */\npublic interface ControlStream {\n\n    /**\n     * Start the connection with the configured parameters\n     */\n    void connect() throws IOException;\n\n    public void startProgram(String cmd, String customShell) throws IOException;\n\n    public InputStream getProgramStdOut() throws IOException;\n\n    public InputStream getProgramStdErr() throws IOException;\n\n    /**\n     * Wait for the control message <expect> and log the remaining ouput asynchronously in the fdt_<hostname>.log file (optional)\n     *\n     * @param expect:           the control message we are looking for\n     * @param allowEOF:         if this is true it means that the EOF is accepted as a *control message* in the protocol\n     * @param grabRemainingLog: if true start a backround thread and save the output in fdt_<hostname>.log file\n     * @throws IOException\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF, boolean grabRemainingLog) throws IOException;\n\n    /**\n     * @param expect\n     * @param allowEOF\n     * @throws IOException\n     * @see #waitForControlMessage(String, boolean, boolean) Wait for the control message but do save the remaining log in a file (thow it away /dev/null)\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF) throws IOException;\n\n    /**\n     * @param expect\n     * @throws IOException\n     * @see SSHControlStream#waitForControlMessage(String, boolean, boolean)\n     */\n    public void waitForControlMessage(String expect) throws IOException;\n\n    /**\n     * save the remote stderr stream in a local file BUG: for some reason this SSH library streams the program stdout and stderr on the same stream (stdout) back to the client\n     *\n     * @param localFileName\n     * @unused : see BUG\n     */\n    public void saveStdErr() throws IOException;\n\n    public int getExitCode();\n\n    public void close();\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/DDCopy.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.text.DecimalFormat;\nimport java.util.Date;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * This class is a simple dd implementation in java with arguments very similar as\n * standard *nix dd command\n *\n * @author ramiro\n */\npublic class DDCopy {\n\n    private static final long KILO = 1024;\n    private static final long MEGA = KILO * 1024;\n    private static final long GIGA = MEGA * 1024;\n    private static final long TERA = GIGA * 1024;\n    private static final long PETA = TERA * 1024;\n\n    //I need heeeelpp ... or I neeed love, love, love ( try google )\n    private static final String USAGE_MESSAGE =\n            \"\\nUsage: java -cp fdt.jar \" + DDCopy.class.getName() + \" [ OPTIONS ] ARGS\\n\" +\n                    \"\\nARGS: if=<sourceFile> of=<destinationFile>\\n\" +\n                    \"\\n\\nWhere OPTIONS can be:\\n\" +\n                    \"\\n   bs=<BufferSize>[K|M]\\t size of the buffer used for read/write.\" +\n                    \"\\n   \\t\\t\\t [K(ilo) | M(ega)] may be used as suffixes. Default 4K\" +\n                    \"\\n   bn=<NoOfBuffers>\\t Number of buffers used to readv()/writev() at once.\" +\n                    \"\\n   \\t\\t\\t If this parameter is 1, or is missing the program will \" +\n                    \"\\n   \\t\\t\\t read()/write() a single buffer at a time, otherwise \" +\n                    \"\\n   \\t\\t\\t the readv()/writev() will be used. Default is 1\" +\n                    \"\\n   count=<count>\\t Number of \\\"blocks\\\" to write.\" +\n                    \"\\n   \\t\\t\\t A \\\"block\\\" is represents how much data is read/write\" +\n                    \"\\n   \\t\\t\\t The size of a \\\"block\\\" is: <BufferSize>*<BuffersNumber>\" +\n                    \"\\n   \\t\\t\\t If <count> <= 0 the copy stops when EOF is reached\" +\n                    \"\\n   \\t\\t\\t reading the <SourceFile>. The default is 0\" +\n                    \"\\n   statsdelay=<seconds>\\t Number of seconds between reports.\" +\n                    \"\\n   \\t\\t\\t Default is 2 seconds. If <seconds> <= 0 no reports \" +\n                    \"\\n   \\t\\t\\t will be printed\" +\n                    \"\\n   flags=<flag>\\t\\t The <flag> field can have of the following values: \" +\n                    \"\\n   \\t\\t\\t    SYNC   For every write both data and metadata are\" +\n                    \"\\n   \\t\\t\\t           written synchronously\" +\n                    \"\\n   \\t\\t\\t    DSYCN  Same as SYNC, but only the data is written\" +\n                    \"\\n   \\t\\t\\t           synchronously.\" +\n                    \"\\n   \\t\\t\\t    NOSYNC The sync() is left to be done by the\" +\n                    \"\\n   \\t\\t\\t           underlying OS\" +\n                    \"\\n   \\t\\t\\t The default value is DSYNC\" +\n                    \"\\n   rformat=<rformat>\\t Report format. Possible values are:\" +\n                    \"\\n   \\t\\t\\t    K - KiloBytes\" +\n                    \"\\n   \\t\\t\\t    M - MegaBytes\" +\n                    \"\\n   \\t\\t\\t    G - GigaBytes\" +\n                    \"\\n   \\t\\t\\t    T - TeraBytes\" +\n                    \"\\n   \\t\\t\\t    P - PetaBytes\" +\n                    \"\\n   \\t\\t\\t The default value is self adjusted. If the factor \" +\n                    \"\\n   \\t\\t\\t is too big only 0s will be displayed\" +\n                    \"\\n\";\n    //the if= param\n    private static String sourceName;\n    //thie of= param\n    private static String destinationName;\n    //how much data was trasfered\n    private static AtomicLong bytesNo = new AtomicLong(0);\n    //how many buffers shall I use in a single write?\n    private static int BUFF_NO = 1;\n    //the buffer size\n    private static int BUFF_SIZE = 4 * (int) KILO;\n    //how much shall I p(l)ay ?\n    private static int COUNT = 0;\n    //Are you lost? Try verbose\n    private static boolean verbose = false;\n    //How worried are you? Take a brake ... try to increase this value\n    private static long delay = 2 * 1000;\n    //how fast can you read loooong numbers on your screen\n    private static long reportingFactor = 0;\n    //I am taking care of your worries ;)\n    private static Thread reportingThread;\n    //shall we take a break and go for a beer ??\n    private static AtomicBoolean hasToRun = new AtomicBoolean(true);\n    //how shall the destinationFile be written: FAST(SYNC), FASTER(DSYNC), DON'T CARE(NOSYNC)\n    private static String wrFlags = \"rw\";\n    //when did you learn to write?\n    private static long START_TIME;\n\n    //do it nicer - TODO make same arrays and use for() ... it's not the 5th grade\n    private static final String format(final double number, final long factor, final String append) {\n        String appendUM;\n        double fNo = number;\n\n        if (factor == 0) {\n            if (number > PETA) {\n                fNo /= PETA;\n                appendUM = \"P\" + append;\n            } else if (number > TERA) {\n                fNo /= TERA;\n                appendUM = \"T\" + append;\n            } else if (number > GIGA) {\n                fNo /= GIGA;\n                appendUM = \"G\" + append;\n            } else if (number > MEGA) {\n                fNo /= MEGA;\n                appendUM = \"M\" + append;\n            } else if (number > KILO) {\n                fNo /= KILO;\n                appendUM = \"K\" + append;\n            } else {\n                appendUM = append;\n            }\n        } else {\n            if (factor == PETA) {\n                fNo /= PETA;\n                appendUM = \"P\" + append;\n            } else if (factor == TERA) {\n                fNo /= TERA;\n                appendUM = \"T\" + append;\n            } else if (factor == GIGA) {\n                fNo /= GIGA;\n                appendUM = \"G\" + append;\n            } else if (factor == MEGA) {\n                fNo /= MEGA;\n                appendUM = \"M\" + append;\n            } else if (factor == KILO) {\n                fNo /= KILO;\n                appendUM = \"K\" + append;\n            } else {//hmmmmmm\n                appendUM = append;\n            }\n        }\n\n        return DecimalFormat.getNumberInstance().format(fNo) + \" \" + appendUM;\n    }\n\n    private static final void printHelp() {\n        System.out.println(USAGE_MESSAGE);\n    }\n\n    public static void main(String[] args) throws Exception {\n        try {\n            //check for help\n            for (int i = 0; i < args.length; i++) {\n                if (args[i].startsWith(\"-h\")) {\n                    printHelp();\n                    System.exit(0);\n                }\n            }\n\n            //check for verbose\n            for (int i = 0; i < args.length; i++) {\n                if (args[i].startsWith(\"-v\")) {\n                    verbose = true;\n                    break;\n                }\n            }\n\n            // TODO Auto-generated method stub\n            for (int i = 0; i < args.length; i++) {\n                if (args[i].startsWith(\"if=\")) {\n                    sourceName = args[i].substring(\"if=\".length());\n                } else if (args[i].startsWith(\"of=\")) {\n                    destinationName = args[i].substring(\"of=\".length());\n                } else if (args[i].startsWith(\"bs=\")) {\n                    String bSParam = args[i].substring(\"bs=\".length());\n                    int factor = 1;\n                    try {\n                        if (bSParam.endsWith(\"k\") || bSParam.endsWith(\"K\")) {\n                            factor = (int) KILO;\n                            bSParam = bSParam.substring(0, bSParam.length() - 1);\n                        } else if (bSParam.endsWith(\"m\") || bSParam.endsWith(\"M\")) {\n                            factor = (int) MEGA;\n                            bSParam = bSParam.substring(0, bSParam.length() - 1);\n                        }\n\n                        BUFF_SIZE = Integer.parseInt(bSParam) * factor;\n\n                    } catch (Throwable t) {\n                        if (verbose) {\n                            System.err.println(\"Cannot parse bsParam \" + args[i] + \" Cause: \");\n                            t.printStackTrace();\n                        } else {\n                            System.err.println(\"Cannot parse bs param: \" + args[i] + \" . Try to run DDCopy with -v for further details\");\n                        }\n\n                        printHelp();\n                        System.err.flush();\n                        System.out.flush();\n\n                        System.exit(1);\n                    }\n                } else if (args[i].startsWith(\"bn=\")) {\n                    try {\n                        BUFF_NO = Integer.parseInt(args[i].substring(\"bn=\".length()));\n                    } catch (Throwable t) {\n                        BUFF_NO = 1;\n                        if (verbose) {\n                            System.err.println(\"Cannot parse bn param \" + args[i] + \" Cause: \");\n                            t.printStackTrace();\n                        } else {\n                            System.err.println(\"Cannot parse bn param \" + args[i] + \". Will use the default value: \" + BUFF_NO);\n                        }\n                    }\n                } else if (args[i].startsWith(\"count=\")) {\n                    try {\n                        COUNT = Integer.parseInt(args[i].substring(\"count=\".length()));\n                    } catch (Throwable t) {\n                        COUNT = -1;\n                        if (verbose) {\n                            System.err.println(\"Cannot parse count param \" + args[i] + \" Cause: \");\n                            t.printStackTrace();\n                        } else {\n                            System.err.println(\"Cannot parse count param \" + args[i] + \". Will use the default value: \" + COUNT);\n                        }\n                    }\n                } else if (args[i].startsWith(\"statsdelay=\")) {\n                    try {\n                        delay = Long.parseLong(args[i].substring(\"count=\".length())) * 1000L;\n                    } catch (Throwable t) {\n                        delay = 2 * 1000;\n                        if (verbose) {\n                            System.err.println(\"Cannot parse statsdelay param \" + args[i] + \" Cause: \");\n                            t.printStackTrace();\n                        } else {\n                            System.err.println(\"Cannot parse statsdelay param \" + args[i] + \". Will use the default value: \" + delay / 1000 + \" seconds\");\n                        }\n                    }\n                } else if (args[i].startsWith(\"flags=\")) {\n                    final String wFlag = args[i].substring(\"flags=\".length());\n                    if (wFlag.equalsIgnoreCase(\"NOSYNC\")) {\n                        wrFlags = \"rw\";\n                    } else if (wFlag.equalsIgnoreCase(\"SYNC\")) {\n                        wrFlags = \"rws\";\n                    } else if (wFlag.equalsIgnoreCase(\"DSYNC\")) {\n                        wrFlags = \"rwd\";\n                    }\n                } else if (args[i].startsWith(\"rformat=\")) {\n                    final String rFlag = args[i].substring(\"rformat=\".length());\n                    if (rFlag.equalsIgnoreCase(\"K\")) {\n                        reportingFactor = KILO;\n                    } else if (rFlag.equalsIgnoreCase(\"M\")) {\n                        reportingFactor = MEGA;\n                    } else if (rFlag.equalsIgnoreCase(\"G\")) {\n                        reportingFactor = GIGA;\n                    } else if (rFlag.equalsIgnoreCase(\"T\")) {\n                        reportingFactor = TERA;\n                    } else if (rFlag.equalsIgnoreCase(\"P\")) {\n                        reportingFactor = PETA;\n                    }\n                }\n            }\n\n            if (sourceName == null || sourceName.trim().length() == 0) {\n                System.out.println(\"\\n No source specified ( if=<SourceFile> parameter ). Use -h for help.\\n\");\n                System.exit(1);\n            }\n\n            if (destinationName == null || destinationName.trim().length() == 0) {\n                System.out.println(\"\\n No destination specified ( 'of=<DestinationFile>' parameter ). Use -h for help.\\n\");\n                System.exit(1);\n            }\n\n\n            if (verbose) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"Source: \").append(sourceName);\n                sb.append(\" Destination: \").append(destinationName);\n                sb.append(\"\");\n            }\n\n            final FileChannel sourceChannel = new RandomAccessFile(sourceName, \"r\").getChannel();\n            final FileChannel destinationChannel = new RandomAccessFile(destinationName, wrFlags).getChannel();\n\n\n            ByteBuffer[] bbuff = new ByteBuffer[BUFF_NO];\n\n            for (int i = 0; i < BUFF_NO; i++) {\n                try {\n                    bbuff[i] = ByteBuffer.allocateDirect(BUFF_SIZE);\n                } catch (OutOfMemoryError oomError) {\n                    System.err.println(\"ByteBuffer reached max limit. The copy may be slow. You may consider to increase to -XX:MaxDirectMemorySize=256m, or decrease the buffer number (bn) parameter\");\n                    System.err.flush();\n                    System.exit(1);\n                }\n            }\n\n            //shall I start a reporting thread?\n            if (delay > 0) {\n                reportingThread = new ReportingThread();\n                reportingThread.start();\n            }\n\n            //register for shudown hook\n            Runtime.getRuntime().addShutdownHook(new ShutdownHook());\n\n            long count = 0;\n            START_TIME = System.currentTimeMillis();\n\n            for (int j = 0; (COUNT > 0) ? j < COUNT : true; j++) {\n                count = sourceChannel.read(bbuff);\n\n                if (count == -1) {\n                    //EOF\n                    break;\n                }\n\n                for (int i = 0; i < BUFF_NO; i++) {\n                    bbuff[i].flip();\n                }\n\n                if (BUFF_NO == 1) {\n                    count = destinationChannel.write(bbuff[0]);\n                } else {\n                    count = destinationChannel.write(bbuff);\n                }\n\n                if (verbose) {\n                    System.out.println(\"Current transfer count =  \" + count + \" Total: \" + bytesNo.get());\n                }\n\n                if (count < 0) {\n                    break;\n                }\n\n                bytesNo.addAndGet(count);\n\n                for (int i = 0; i < BUFF_NO; i++) {\n                    bbuff[i].clear();\n                }\n\n            }\n        } catch (Throwable t) {\n            System.err.println(\"Got exception: \");\n            t.printStackTrace();\n        } finally {\n            System.out.flush();\n            System.err.flush();\n        }\n    }\n\n    /**\n     * Statistics\n     */\n    private static final class ReportingThread extends Thread {\n\n        long lastTime;\n        long lastCount;\n        long now;\n        long cCount;\n\n\n        public ReportingThread() {\n            setDaemon(true);\n            setName(\"DDCopy reporting thread\");\n        }\n\n        public void run() {\n\n            //first iteration\n            lastCount = bytesNo.get();\n            lastTime = System.currentTimeMillis();\n\n            for (; ; ) {\n\n                try {\n                    Thread.sleep(delay);\n                } catch (Throwable t1) {\n                }\n\n                if (!hasToRun.get()) return;\n\n                now = System.currentTimeMillis();\n                cCount = bytesNo.get();\n\n                double speed = (cCount - lastCount) / ((now - lastTime) / 1000D);\n                double avgSpeed = cCount / ((now - START_TIME) / 1000D);\n\n                lastTime = now;\n                lastCount = cCount;\n\n                System.out.println(\"[\" + new Date().toString() + \"] Current Speed = \" + format(speed, reportingFactor, \"B/s\") +\n                        \" Avg Speed: \" + format(avgSpeed, reportingFactor, \"B/s\") +\n                        \" Total Transfer: \" + format(cCount, reportingFactor, \"B\")\n                );\n            }//for\n        }\n    }\n\n    /**\n     * Shutdown hook\n     */\n    private static final class ShutdownHook extends Thread {\n        public void run() {\n            setName(\"Shutdown Hook Thread\");\n\n            if (verbose) {\n                System.out.println(\"\\n\\n Entering shutdown hook \\n\\n\");\n            }\n\n            hasToRun.set(false);\n            if (reportingThread != null) {\n                reportingThread.interrupt();\n            }\n\n            final long totalTime = System.currentTimeMillis() - START_TIME;\n            final long totalBytes = bytesNo.get();\n            final double avgSpeed = totalBytes / (totalTime / 1000D);\n\n            System.out.println(\"\\n\" +\n                    \"\\n Total Transfer: \" + format(totalBytes, reportingFactor, \"Bytes\") + \" ( \" + totalBytes + \" bytes )\" +\n                    \"\\n Time: \" + totalTime / 1000 + \" seconds\" +\n                    \"\\n Avg Speed: \" + format(avgSpeed, reportingFactor, \"B/s\") +\n                    \"\\n\");\n\n            System.out.flush();\n            System.err.flush();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/DirectByteBufferPool.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport lia.util.net.copy.monitoring.jmx.DBPoolJMX;\n\nimport javax.management.ObjectName;\nimport java.lang.management.ManagementFactory;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The main pool of direct NIO buffers in FDT\n *\n * @author ramiro\n */\npublic class DirectByteBufferPool extends AbstractBPool {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(DirectByteBufferPool.class.getName());\n    ;\n    //the list of ByteBuffer-s\n    private static DirectByteBufferPool _theInstance;\n    //used for double checked locking\n    private static volatile boolean initialized = false;\n\n    private DirectByteBufferPool(int bufferSize, int maxPollIter, boolean trackAllocations) {\n        super(bufferSize, maxPollIter, trackAllocations, Config.getInstance().isGenTest());\n    }\n\n\n    public static final DirectByteBufferPool getInstance() {\n        //double checked locking\n        if (!initialized) {\n            synchronized (DirectByteBufferPool.class) {\n                while (!initialized) {\n                    try {\n                        DirectByteBufferPool.class.wait();\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \" Got exception waiting for initialization \", t);\n                    }\n                }\n            }\n        }\n\n        return _theInstance;\n    }\n\n    public static final boolean initInstance(final int buffSize, final int maxTakePollIter) {\n\n        synchronized (DirectByteBufferPool.class) {\n            if (!initialized) {\n                int mMax = maxTakePollIter;\n                if (maxTakePollIter < 0) {\n                    mMax = 0;\n                }\n\n                _theInstance = new DirectByteBufferPool(buffSize, mMax, Config.TRACK_ALLOCATIONS);\n\n                initialized = true;\n\n                DirectByteBufferPool.class.notifyAll();\n                try { // Register MBean in Platform MBeanServer\n                    ManagementFactory.getPlatformMBeanServer().\n                            // TODO Replace DBPoolJMX Constructor parameters with valid values\n                                    registerMBean(new DBPoolJMX(_theInstance),\n                                    new ObjectName(\"lia.util.net.copy.monitoring.jmx:type=DBPoolJMX\"));\n                } catch (Throwable ex) {\n                    logger.log(Level.WARNING, \" Unable to init JMX monitoring for DirectByteBufferPool!\", ex);\n                }\n\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FDTBuffer.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Wrapper class over {@link ByteBuffer} which keeps track whether a buffer is\n * in use or not\n *\n * @author ramiro\n */\npublic class FDTBuffer {\n\n    private ByteBuffer[] buffers;\n    private AtomicBoolean inUse;\n\n    FDTBuffer() {\n        this.inUse = new AtomicBoolean(false);\n    }\n\n    void setBuffer(ByteBuffer[] buffers) {\n        if (inUse.compareAndSet(false, true)) {\n            this.buffers = buffers;\n        } else {\n            throw new RuntimeException(\"cannot set buffers because the buffer is still in use\");\n        }\n    }\n\n    boolean free() {\n        return inUse.compareAndSet(true, false);\n    }\n\n    public ByteBuffer[] get() {\n        return buffers;\n    }\n\n    public boolean hasRemaining() {\n        return buffers[buffers.length - 1].hasRemaining();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FDTBufferPool.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.nio.ByteBuffer;\nimport java.util.LinkedList;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\npublic class FDTBufferPool {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(FDTBufferPool.class.getName());\n    //TODO - the size will have to be set based on the capacity() of the\n    //current buffers in the pool\n    //For the momnet it will be the size of the \"list\" of the buffers - should be a long instead of an integer\n    public static AtomicInteger POOL_SIZE;\n    //the list of ByteBuffer-s\n    public static FDTBufferPool _theInstance;\n    //TODO - dynamicaly set this size\n    private static int BUFFER_SIZE;\n    //used for double checked locking\n    private static volatile boolean initialized = false;\n    //Synch variables. We will not set an upper limit for the pool ...\n    //\n    final Lock lock;\n    final Condition notTaking;\n    final Condition notEmpty;\n    private final LinkedList<ByteBuffer> buffersPool;\n    private final LinkedList<FDTBuffer> fdtBuffersPool;\n    private volatile boolean taking = false;\n    private volatile boolean limitReached = false;\n\n    private FDTBufferPool() {\n        lock = new ReentrantLock();\n        notTaking = lock.newCondition();\n        notEmpty = lock.newCondition();\n        buffersPool = new LinkedList<ByteBuffer>();\n        fdtBuffersPool = new LinkedList<FDTBuffer>();\n    }\n\n    public static final FDTBufferPool getInstance() {\n\n        //double checked locking\n        if (!initialized) {\n            synchronized (FDTBufferPool.class) {\n                while (!initialized) {\n                    try {\n                        FDTBufferPool.class.wait();\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \" Got exception waiting for initialization \", t);\n                    }\n                }\n            }\n        }\n\n        return _theInstance;\n    }\n\n    /**\n     * This function must be called to instantiate the pool. Subsequent calls\n     *\n     * @param buffSize\n     * @return\n     */\n    public static final boolean initInstance(int buffSize) {\n\n        synchronized (FDTBufferPool.class) {\n            if (!initialized) {\n\n                BUFFER_SIZE = buffSize;\n                _theInstance = new FDTBufferPool();\n                initialized = true;\n                FDTBufferPool.class.notifyAll();\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private ByteBuffer tryAllocateBuffer() {\n\n        if (!limitReached) {\n            try {\n                return ByteBuffer.allocateDirect(BUFFER_SIZE);\n            } catch (OutOfMemoryError oom) {\n                logger.log(Level.INFO, \" ByteBuffer reached max limit. You may consider to increase to -XX:MaxDirectMemorySize=256m \");\n                limitReached = true;\n                return null;\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" Got general exception trying to allocate the mem. Please notify the developers! \", t);\n                return null;\n            } finally {\n                if (!limitReached) {\n                    POOL_SIZE.incrementAndGet();\n                }\n            }\n        }\n\n        return null;\n    }\n\n    public int getBufferSize() {\n        return BUFFER_SIZE;\n    }\n\n    public int getSize() {\n        return buffersPool.size();\n    }\n\n    public int getCapacity() {\n        return POOL_SIZE.get();\n    }\n\n    /**\n     * @param size - in bytes\n     * @return\n     * @throws InterruptedException\n     */\n    public FDTBuffer take(int size) throws InterruptedException {\n\n        FDTBuffer fdtBuffer = null;\n        ByteBuffer[] buffs = null;\n        int allocated = 0;\n        int reminder = size % BUFFER_SIZE;\n        int buffCount = (size < BUFFER_SIZE) ? 1 : (size / BUFFER_SIZE + ((reminder != 0) ? 1 : 0));\n\n        lock.lock();\n        try {\n            //do not allow different threads to fill \"partial\" FDTBuffer-s\n            while (taking) {\n                notTaking.await();\n            }\n\n            taking = true;\n\n            fdtBuffer = fdtBuffersPool.poll();\n            if (fdtBuffer == null) {\n                fdtBuffer = new FDTBuffer();\n            }\n\n            buffs = new ByteBuffer[buffCount];\n\n            while (allocated < buffCount) {\n                ByteBuffer buff = buffersPool.poll();\n                if (buff == null && !limitReached) {\n                    buff = tryAllocateBuffer();\n                }\n\n                if (buff == null) {\n                    while (buffersPool.size() == 0) {\n                        notEmpty.await();\n                    }\n\n                    buff = buffersPool.poll();\n                }\n\n                buffs[allocated++] = buff;\n\n            }//end while\n\n            if (reminder != 0) {\n                buffs[buffCount - 1].limit(reminder);\n            }\n\n            fdtBuffer.setBuffer(buffs);\n\n        } finally {\n\n            if (fdtBuffer == null || fdtBuffer.get() == null) {//error\n                try {\n                    if (fdtBuffer.get() != null) {\n                        fdtBuffer.free();\n                        fdtBuffersPool.offer(fdtBuffer);\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" Got exception returning fdtBuffer to the pull\", t);\n                }\n\n                int i = 0;\n                try {\n                    for (; i < allocated; i++) {\n                        buffersPool.add(buffs[i]);\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" Got exception returning buffers to the pull [ currentIdx = \" + i\n                            + \" allocated = \" + allocated\n                            + \" buffCount = \" + buffCount + \" ]\", t);\n                }\n            }\n\n            try {\n                //signal the waiting threads\n                taking = false;\n                notTaking.signal();\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" \\n\\n Got exception signaling notTaking Condition. Something has gone dreadfully wrong \\n\\n\", t);\n            }\n\n            lock.unlock();\n        }\n\n        return fdtBuffer;\n\n    }\n\n    public boolean put(FDTBuffer fdtBuffer) {\n\n        lock.lock();\n        try {\n            if (fdtBuffer.free()) {\n                ByteBuffer[] buffs = fdtBuffer.get();\n                for (int i = 0; i < buffs.length; i++) {\n                    buffersPool.add(buffs[i]);\n                }\n\n                fdtBuffersPool.add(fdtBuffer);\n            }\n        } finally {\n\n            if (buffersPool.size() != 0) {\n                notEmpty.signal();\n            }\n\n            lock.unlock();\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FDTCloseable.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\n\n/**\n * An extended version of {@link java.io.Closeable} with the possibility to specify\n * an eventual message and/or exception\n * <p>\n * The close() methods return true if they have been already called\n *\n * @author ramiro\n */\npublic interface FDTCloseable {\n\n    public boolean close(String downMessage, Throwable downCause);\n\n    public boolean isClosed();\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FDTCommandLine.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\n/**\n * Simple class to keep the optins given in the command line\n *\n * @author ramiro\n */\n\n//TODO - maybe in the future will use a more standard POSIX interface for the command line\npublic class FDTCommandLine {\n\n    //immutable instances - no need for synchronization\n\n    //any params should be in this map ( if the param is only a flag it's value will be non-null )\n    private final HashMap<String, String> optionsMap;\n\n    //all the arguments which do not had an associated flag\n    private final ArrayList<String> leftArgs;\n\n    /**\n     * @param args\n     */\n    public FDTCommandLine(final String[] args) {\n        HashMap<String, String> tmpCmdOptions = new HashMap<String, String>();\n        ArrayList<String> tmpParamsLeft = new ArrayList<String>();\n\n        //parse the options first\n        int i = 0;\n        for (i = 0; i < args.length; i++) {\n            if (args[i].startsWith(\"-\")) {\n                if (i == args.length - 1 || args[i + 1].startsWith(\"-\")) {\n                    tmpCmdOptions.put(args[i], \"\");\n                } else {\n                    tmpCmdOptions.put(args[i], args[i + 1]);\n                    i++;\n                }\n            } else {\n                break;\n            }\n        }//for()\n\n        for (; i < args.length; i++) {\n            tmpParamsLeft.add(args[i]);\n        }\n\n        optionsMap = tmpCmdOptions;\n        leftArgs = tmpParamsLeft;\n    }\n\n    public HashMap<String, String> getOptionsMap() {\n        return optionsMap;\n    }\n\n    public String getOption(String key) {\n        return optionsMap.get(key);\n    }\n\n    public ArrayList<String> getLeftArguments() {\n        return leftArgs;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FDTVersion.java",
    "content": "/*\n * Created on Nov 19, 2012\n */\npackage lia.util.net.common;\n\nimport java.util.StringTokenizer;\n\n\n/**\n * @author ramiro\n */\npublic final class FDTVersion implements Comparable<FDTVersion> {\n\n    final int major;\n    final int minor;\n    final int maintenance;\n\n    final String releaseDate;\n\n    /**\n     * @param major\n     * @param minor\n     * @param maintenance\n     * @param releaseDate\n     */\n    private FDTVersion(int major, int minor, int maintenance, String releaseDate) {\n        this.major = major;\n        this.minor = minor;\n        this.maintenance = maintenance;\n        this.releaseDate = releaseDate;\n    }\n\n\n    public static FDTVersion fromVersionString(final String versionString) {\n        if (versionString == null) {\n            throw new NullPointerException(\"Null version string\");\n        }\n\n        final int rDateDelim = versionString.indexOf('-');\n        final String vString = (rDateDelim > 0) ? versionString.substring(0, rDateDelim) : versionString;\n        final String rDate = (rDateDelim < 0) ? \"\" : versionString.substring(rDateDelim + 1);\n\n        final StringTokenizer st = new StringTokenizer(vString, \".\");\n        int major = 0;\n        int minor = 0;\n        int maint = 0;\n\n        if (st.hasMoreTokens()) {\n            major = Integer.parseInt(st.nextToken());\n        }\n        if (st.hasMoreTokens()) {\n            minor = Integer.parseInt(st.nextToken());\n        }\n        if (st.hasMoreTokens()) {\n            maint = Integer.parseInt(st.nextToken());\n        }\n\n        return new FDTVersion(major, minor, maint, rDate);\n    }\n\n\n    /* (non-Javadoc)\n     * @see java.lang.Object#toString()\n     */\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"FDTVersion [\")\n                .append(major)\n                .append(\".\")\n                .append(minor)\n                .append(\".\")\n                .append(maintenance)\n                .append(\"-\")\n                .append(releaseDate)\n                .append(\"]\");\n        return builder.toString();\n    }\n\n\n    @Override\n    public int compareTo(FDTVersion other) {\n        int d = this.major - other.major;\n        if (d == 0) {\n            d = this.minor - other.minor;\n            if (d == 0) {\n                d = this.maintenance - other.maintenance;\n                if (d == 0) {\n                    if (this.releaseDate != null && other.releaseDate != null) {\n                        return this.releaseDate.compareTo(other.releaseDate);\n                    }\n                }\n            }\n        }\n        return d;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FileChannelProvider.java",
    "content": "/*\n * Created on Dec 22, 2009\n *\n */\npackage lia.util.net.common;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\n\n\n/**\n * Generic provider interface for {@link FileChannel} inside FDT.\n * <p>\n * There is no assumption on the read/write direction for the returned {@link FileChannel}.\n *\n * @author ramiro\n */\npublic interface FileChannelProvider {\n\n    /**\n     * @param fileName\n     * @return\n     * @throws IOException\n     */\n    public File getFile(final String fileName) throws IOException;\n\n    /**\n     * @param file\n     * @return\n     * @throws IOException\n     */\n    public int getPartitionID(final File file) throws IOException;\n\n    /**\n     * @param file\n     * @return\n     * @throws IOException\n     */\n    public FileChannel getFileChannel(final File file, final String openMode) throws IOException;\n}\n"
  },
  {
    "path": "src/lia/util/net/common/FileChannelProviderFactory.java",
    "content": "/*\n * Created on Dec 26, 2009\n * \n */\npackage lia.util.net.common;\n\n//import lia.util.net.copy.FDTCoordinatorSession;\n\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.FDTWriterSession;\n\n\n/**\n * @author ramiro\n */\npublic interface FileChannelProviderFactory {\n    FileChannelProvider newReaderFileChannelProvider(FDTReaderSession readerSession);\n\n    FileChannelProvider newWriterFileChannelProvider(FDTWriterSession writerSession);\n//    FileChannelProvider newCoordinatorChannelProvider(FDTCoordinatorSession coordinatorSession);\n}\n"
  },
  {
    "path": "src/lia/util/net/common/GSISSHControlStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport ch.ethz.ssh2.StreamGobbler;\nimport com.sshtools.common.configuration.SshToolsConnectionProfile;\nimport com.sshtools.j2ssh.SshClient;\nimport com.sshtools.j2ssh.authentication.AuthenticationProtocolState;\nimport com.sshtools.j2ssh.session.SessionChannelClient;\nimport org.ietf.jgss.GSSException;\n\nimport java.io.*;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * @author Adrian Muraru\n */\npublic class GSISSHControlStream implements ControlStream {\n\n    // configuration parameters\n    private final String hostname;\n    private final String username;\n    private final int port;\n\n    /**\n     * the SSH connection & session\n     */\n    private SshClient conn;\n    private SessionChannelClient sess;\n    private String cmd;\n    private String customShell;\n\n    /**\n     * Creates a new GSI SSH control connection on the default ssh port.\n     * <p>\n     * Same as {@link #GSISSHControlStream(String, String, int) GSISSHControlStream(hostname, username, 22)}\n     *\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public GSISSHControlStream(String hostname, String username) {\n        this(hostname, username, 22);\n    }\n\n    /**\n     * Creates a new SSH control connection on the specified remote GSI sshd server port\n     *\n     * @param port:     remote GSI-sshd port\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public GSISSHControlStream(String hostname, String username, int port) {\n        this.hostname = hostname;\n        this.username = username;\n        this.port = port;\n    }\n\n    // TEST\n    public static void main(String[] args) throws IOException {\n        ControlStream cs = new GSISSHControlStream(args[0], args[1]);\n        cs.startProgram(args[2], args[3]);\n\n\t\t/* read stdout */\n        InputStream stdout = new StreamGobbler(cs.getProgramStdOut());\n        BufferedReader br = new BufferedReader(new InputStreamReader(stdout));\n        while (true) {\n            String line = br.readLine();\n            if (line == null)\n                break;\n            System.out.println(line);\n        }\n        System.out.println(\"ExitCode:\" + cs.getExitCode());\n        cs.close();\n    }\n\n    public void connect() throws IOException {\n        lia.gsi.ssh.GSIAuthenticationClient gsiAuth = null;\n        try {\n            gsiAuth = new lia.gsi.ssh.GSIAuthenticationClient();\n            gsiAuth.setUsername(username);\n        } catch (GSSException e) {\n            throw new IOException(\"Cannot load grid credentials.\");\n        }\n        conn = new SshClient();\n        SshToolsConnectionProfile properties = new SshToolsConnectionProfile();\n        // TODO: add new \"port\" parameter\n        properties.setPort(port);\n        properties.setForwardingAutoStartMode(false);\n        properties.setHost(hostname);\n        properties.setUsername(username);\n        conn.setUseDefaultForwarding(false);\n        conn.connect(properties);\n        try {\n            // Authenticate the user\n            int result = conn.authenticate(gsiAuth, hostname);\n            if (result != AuthenticationProtocolState.COMPLETE) {\n                throw new IOException(\"GSI authentication failed\");\n            }\n            // Open a session channel\n            sess = conn.openSessionChannel();\n            sess.requestPseudoTerminal(\"javash\", 0, 0, 0, 0, \"\");\n        } catch (Throwable t) {\n            throw new IOException(t.getMessage());\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#startProgram(java.lang.String)\n     */\n    public void startProgram(String cmd, String customShell) throws IOException {\n        this.cmd = customShell + \" --login -c '\" + cmd + \" 2>&1'\";\n        this.sess.executeCommand(this.cmd);\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#getProgramStdOut()\n     */\n    public InputStream getProgramStdOut() {\n        return this.sess.getInputStream();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#getProgramStdErr()\n     */\n    public InputStream getProgramStdErr() throws IOException {\n        return this.sess.getStderrInputStream();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String, boolean, boolean)\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF, boolean grabRemainingLog) throws IOException {\n        /* read stdout */\n        // InputStream stdout = new StreamGobbler(getProgramStdOut());\n        BufferedReader br = new BufferedReader(new InputStreamReader(getProgramStdOut()));\n        final String outputPrefix = \"[\" + this.hostname + \"]$ \";\n        while (true) {\n            String line = br.readLine();\n            if (line == null) {\n                if (allowEOF)\n                    return;\n                // else\n                throw new IOException(\"[\" + this.cmd + \"] exited. No control message received]\");\n            }\n            System.err.println(outputPrefix + line);\n            if (line.trim().equalsIgnoreCase(expect)) {\n                LogWriter lw = grabRemainingLog\n                        ? new LogWriter(br, \"fdt_\" + this.hostname + \".log\")\n                        : new LogWriter(br);\n                lw.setDaemon(true);\n                lw.start();\n                return;\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String, boolean)\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF) throws IOException {\n        this.waitForControlMessage(expect, allowEOF, false);\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String)\n     */\n    public void waitForControlMessage(String expect) throws IOException {\n        this.waitForControlMessage(expect, false, true);\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#saveStdErr()\n     */\n    public void saveStdErr() throws IOException {\n        BufferedReader br = new BufferedReader(new InputStreamReader(getProgramStdErr()));\n        LogWriter lw = new LogWriter(br, \"fdt_\" + this.hostname + \".err\");\n        lw.setDaemon(true);\n        lw.start();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#getExitCode()\n     */\n    public int getExitCode() {\n        return this.sess.getExitCode();\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see lia.util.net.common.ControlStream#close()\n     */\n    public void close() {\n        try {\n            if (this.sess != null) {\n                this.sess.close();\n            }\n        } catch (IOException e) {\n\n        }\n\n        if (this.conn != null) {\n            this.conn.disconnect();\n        }\n    }\n\n    /**\n     * asynch write in a local log file of the remote stderr stream\n     */\n    static class LogWriter extends Thread {\n        BufferedReader br;\n        String logFile;\n\n        public LogWriter(BufferedReader br) {\n            this.br = br;\n            this.logFile = null;\n        }\n\n        public LogWriter(BufferedReader br, String fileName) {\n            this.br = br;\n            this.logFile = fileName;\n        }\n\n        public void run() {\n            BufferedWriter out = null;\n            try {\n                if (this.logFile != null) {\n                    out = new BufferedWriter(new FileWriter(logFile, false));\n                    final Date date = new Date();\n                    out.write(\"==============\" + new SimpleDateFormat(\"E, dd MMM yyyy HH:mm:ss Z\").format(date) + \"================\\n\");\n                }\n                while (true) {\n                    String line = br.readLine();\n\n                    if (line == null) {\n                        if (out != null)\n                            out.close();\n                        return;\n                    }\n                    if (out != null) {\n                        out.write(line + \"\\n\");\n                        out.flush();\n                    }\n                }\n            } catch (IOException e) {\n                System.err.println(\"Cannot write remote log:\" + logFile);\n                try {\n                    if (out != null)\n                        out.close();\n                } catch (IOException e1) {\n                }\n                return;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/HeaderBufferPool.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is only for the love of fast development.\n * TODO - We should have only one buffer pool in entire FDT Application;\n * when this will happen this class will disappear ....\n *\n * @author ramiro\n */\npublic class HeaderBufferPool extends AbstractBPool {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(HeaderBufferPool.class.getName());\n\n    //the list of ByteBuffer-s\n    private static HeaderBufferPool _theInstance;\n    //used for double checked locking\n    private static volatile boolean initialized = false;\n\n    private HeaderBufferPool(int bufferSize, int maxPollIter, boolean trackAllocations) {\n        super(bufferSize, maxPollIter, trackAllocations, false);\n    }\n\n\n    public static final HeaderBufferPool getInstance() {\n        //double checked locking\n        if (!initialized) {\n            synchronized (DirectByteBufferPool.class) {\n                while (!initialized) {\n                    try {\n                        DirectByteBufferPool.class.wait();\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \" Got exception waiting for initialization \", t);\n                    }\n                }\n            }\n        }\n\n        return _theInstance;\n    }\n\n    public static final boolean initInstance() {\n\n        synchronized (HeaderBufferPool.class) {\n            if (!initialized) {\n\n                _theInstance = new HeaderBufferPool(Config.HEADER_SIZE, 0, Config.TRACK_ALLOCATIONS);\n\n                initialized = true;\n\n                HeaderBufferPool.class.notifyAll();\n\n                return true;\n            }\n\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/InvalidFDTParameterException.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\n/**\n * Used to signal various exception/errors related to FDT config/params\n *\n * @author ramiro\n */\npublic class InvalidFDTParameterException extends Exception {\n\n    private static final long serialVersionUID = -4780995072523010199L;\n\n    public InvalidFDTParameterException() {\n        super();\n    }\n\n    public InvalidFDTParameterException(String message) {\n        super(message);\n    }\n\n    public InvalidFDTParameterException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public InvalidFDTParameterException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/KernelTest.java",
    "content": "/*\n * $Id$\n *\n * Created on December 9, 2006, 4:14 PM\n *\n * Do not try this on a production system. It can freeze tha machine!\n * Please see: http://bugzilla.kernel.org/show_bug.cgi?id=7645\n *\n * You have been warned !\n *\n */\n\npackage lia.util.net.common;\n\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\n/**\n * @author ramiro\n */\npublic class KernelTest extends Thread {\n\n    public static final int BUFF_SIZE = 512 * 1024;\n\n    static ByteBuffer _theBuffer;\n    static int NUMBER_OF_THREADS = 5;\n\n\n    int id;\n\n    /**\n     * Creates a new instance of CrushTest\n     */\n    public KernelTest(int id) {\n        this.id = id;\n        setName(\"KernelTest worker id: \" + id);\n        setDaemon(true);\n    }\n\n    public static final void main(String[] args) throws Exception {\n\n        for (int i = 0; i < args.length; i++) {\n            if (args[i].equals(\"-d\")) {\n                _theBuffer = ByteBuffer.allocateDirect(BUFF_SIZE);\n            } else if (args[i].equals(\"-n\")) {\n                if (i + 1 < args.length) {\n                    int tNo = NUMBER_OF_THREADS;\n                    try {\n                        tNo = Integer.parseInt(args[i + 1]);\n                        if (tNo < 0) {\n                            tNo = NUMBER_OF_THREADS;\n                        }\n                    } catch (Throwable t) {\n                        System.out.println(\"Cannot parse -n arg\" + t.getCause());\n                        tNo = NUMBER_OF_THREADS;\n                    }\n\n                    NUMBER_OF_THREADS = tNo;\n                }\n            }\n\n        }//for\n\n        if (_theBuffer == null) {\n            _theBuffer = ByteBuffer.allocate(BUFF_SIZE);\n        }\n\n        System.out.println(\"Using: \" + NUMBER_OF_THREADS + \" threads,\" +\n                \" BUFF_SIZE: \" + BUFF_SIZE + \" Bytes,\" +\n                \" \" + ((_theBuffer.isDirect()) ? \"Direct\" : \"Heap\") + \" buffer\");\n\n        for (int i = 0; i < NUMBER_OF_THREADS; i++) {\n            new KernelTest(i).start();\n        }\n\n        Object waiter = new Object();\n        synchronized (waiter) {\n            waiter.wait(10 * 1000);//10 seconds\n//            waiter.wait();//forever\n        }\n\n    }//main\n\n    public void run() {\n        FileChannel channel = null;\n\n        try {\n            channel = new FileInputStream(\"/dev/zero\").getChannel();\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n\n        if (channel == null) {\n            return;\n        }\n\n        System.out.println(\"KernelTest thread \" + id + \" started\");\n\n        for (; ; ) {\n            try {\n                _theBuffer.clear();\n                channel.read(_theBuffer);\n\n            } catch (Throwable t) {\n                t.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/LocalHost.java",
    "content": "/*\n * $Id$\n * Created on Jul 12, 2005\n *\n */\npackage lia.util.net.common;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\n\n/**\n * @author Adrian Muraru\n */\npublic class LocalHost {\n\n    static public List<String> getPublicIPs4() {\n        List<String> ips4 = new ArrayList<String>();\n        Enumeration<NetworkInterface> ifs;\n        try {\n            ifs = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e) {\n            e.printStackTrace();\n            return ips4;\n        }\n        while (ifs.hasMoreElements()) {\n            NetworkInterface iface = ifs.nextElement();\n            Enumeration<InetAddress> iad = iface.getInetAddresses();\n            while (iad.hasMoreElements()) {\n                InetAddress localIP = iad.nextElement();\n                if (!localIP.isSiteLocalAddress() && !localIP.isLoopbackAddress()) {\n                    // found an IPv4 address and proxyAddress not set yet\n                    if (localIP instanceof java.net.Inet4Address)\n                        ips4.add(localIP.getHostAddress());\n                }\n            }\n        }\n        return ips4;\n    }\n\n    /**\n     * @return A list of colon separated list of local public ips\n     * If no public address is found an empty string is returned\n     */\n    static public String getStringPublicIPs4() {\n        final List<String> ip4s = LocalHost.getPublicIPs4();\n        if (ip4s.size() <= 0) return \"\";\n        final StringBuilder sb = new StringBuilder();\n        for (String ip : ip4s) {\n            sb.append(ip).append(':');\n        }\n        return sb.length() >= 1 ? sb.deleteCharAt(sb.length() - 1).toString() : \"\";\n    }\n\n    static public List<String> getPublicIPs6() {\n        List<String> ips6 = new ArrayList<String>();\n        Enumeration<NetworkInterface> ifs;\n        try {\n            ifs = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e) {\n            e.printStackTrace();\n            return ips6;\n        }\n        while (ifs.hasMoreElements()) {\n            NetworkInterface iface = ifs.nextElement();\n            Enumeration<InetAddress> iad = iface.getInetAddresses();\n            while (iad.hasMoreElements()) {\n                InetAddress localIP = iad.nextElement();\n                if (!localIP.isSiteLocalAddress() && !localIP.isLinkLocalAddress() && !localIP.isLoopbackAddress()) {\n                    if (localIP instanceof java.net.Inet6Address)\n                        ips6.add(localIP.getHostAddress());\n                }\n            }\n        }\n        return ips6;\n    }\n\n    static public String getPublicIP4() {\n\n        Enumeration<NetworkInterface> ifs;\n        try {\n            ifs = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e) {\n            e.printStackTrace();\n            return null;\n        }\n\n        while (ifs.hasMoreElements()) {\n            NetworkInterface iface = ifs.nextElement();\n            Enumeration<InetAddress> iad = iface.getInetAddresses();\n            while (iad.hasMoreElements()) {\n                InetAddress localIP = iad.nextElement();\n                if (!localIP.isSiteLocalAddress() && !localIP.isLoopbackAddress()) {\n                    // found an IPv4 address\n                    if (localIP instanceof java.net.Inet4Address)\n                        return localIP.getHostAddress();\n                }\n            }\n        }\n        return null;\n    }\n\n    static public String getPublicIP6() {\n\n        Enumeration<NetworkInterface> ifs;\n        try {\n            ifs = NetworkInterface.getNetworkInterfaces();\n        } catch (SocketException e) {\n            e.printStackTrace();\n            return null;\n        }\n\n        while (ifs.hasMoreElements()) {\n            NetworkInterface iface = ifs.nextElement();\n            Enumeration<InetAddress> iad = iface.getInetAddresses();\n            while (iad.hasMoreElements()) {\n                InetAddress localIP = iad.nextElement();\n                if (!localIP.isSiteLocalAddress() && !localIP.isLinkLocalAddress() && !localIP.isLoopbackAddress()) {\n                    if (localIP instanceof java.net.Inet6Address)\n                        return localIP.getHostAddress();\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        System.out.println(getPublicIP4());\n        System.out.println(getPublicIP6());\n        System.out.println(getPublicIPs4());\n        System.out.println(getPublicIPs6());\n\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/common/MassStorage.java",
    "content": "/*\r\n * $Id$\r\n */\r\npackage lia.util.net.common;\r\n\r\nimport java.io.FileInputStream;\r\nimport java.util.Properties;\r\nimport java.util.logging.Level;\r\nimport java.util.logging.Logger;\r\n\r\n/**\r\n * @author Ilya Narsky\r\n */\r\npublic class MassStorage {\r\n\r\n    private static final Logger logger = Logger.getLogger(MassStorage.class.getName());\r\n\r\n    private String siteStorageID;// cit-se.ultralight.org\r\n\r\n    private String storageRoot;// /pnfs/ultralight.org/data\r\n\r\n    private String storageType;// dcache\r\n\r\n    private String storageAccessCmd;// dccp\r\n\r\n    private String storageCmdOptions;// dccp options\r\n\r\n    private String storageAccessPoint;// dcap://cit-dcap.ultralight.org:port\r\n\r\n    private String localFilePrefix;// none for dccp; file:/// for srmcp\r\n\r\n    private String localFileDir;// for example, /tmp\r\n\r\n    private int nThreads;// number of threads used for transfers to/from storage\r\n\r\n    private int verbose;// verbosity level\r\n\r\n    static public boolean checkType(String type) {\r\n        if (type.compareTo(\"dcache\") == 0)\r\n            return true;\r\n        return false;\r\n    }\r\n\r\n    public String siteStorageID() {\r\n        return this.siteStorageID;\r\n    }\r\n\r\n    public String storageRoot() {\r\n        return this.storageRoot;\r\n    }\r\n\r\n    public String storageType() {\r\n        return this.storageType;\r\n    }\r\n\r\n    public String storageAccessCmd() {\r\n        return this.storageAccessCmd;\r\n    }\r\n\r\n    public String storageCmdOptions() {\r\n        return this.storageCmdOptions;\r\n    }\r\n\r\n    public String storageAccessPoint() {\r\n        return this.storageAccessPoint;\r\n    }\r\n\r\n    public String localFilePrefix() {\r\n        return this.localFilePrefix;\r\n    }\r\n\r\n    public String localFileDir() {\r\n        return this.localFileDir;\r\n    }\r\n\r\n    public int nThreads() {\r\n        return this.nThreads;\r\n    }\r\n\r\n    public int verbose() {\r\n        return this.verbose;\r\n    }\r\n\r\n    public boolean init(String configFile) {\r\n        // get properties\r\n        Properties prop = new Properties();\r\n        try {\r\n            FileInputStream in = new FileInputStream(configFile);\r\n            prop.load(in);\r\n            in.close();\r\n        } catch (Exception e) {\r\n            logger.log(Level.SEVERE, \"Unable to open file \" + configFile);\r\n            return false;\r\n        }\r\n\r\n        // get params\r\n        this.siteStorageID = prop.getProperty(\"storage.siteID\", \"\");\r\n        this.storageRoot = prop.getProperty(\"storage.root\", \"\");\r\n        this.storageType = prop.getProperty(\"storage.type\", \"dcache\");\r\n        this.storageAccessCmd = prop.getProperty(\"storage.accessCmd\", \"/opt/d-cache/dcap/bin/dccp\");\r\n        this.storageCmdOptions = prop.getProperty(\"storage.cmdOptions\", \"\");\r\n        this.storageAccessPoint = prop.getProperty(\"storage.accessPoint\", \"\");\r\n        this.localFilePrefix = prop.getProperty(\"storage.localFilePrefix\", \"\");\r\n        this.localFileDir = prop.getProperty(\"storage.localFileDir\", \".\");\r\n        this.nThreads = (Integer.valueOf(prop.getProperty(\"storage.nThreads\", \"1\"))).intValue();\r\n        this.verbose = (Integer.valueOf(prop.getProperty(\"storage.verbosity\", \"0\"))).intValue();\r\n\r\n        // sanity check\r\n        if (this.storageAccessCmd.length() == 0) {\r\n            logger.log(Level.SEVERE, \"Incorrect storage parameters specified.\");\r\n            return false;\r\n        }\r\n        if (this.nThreads == 0) {\r\n            logger.log(Level.SEVERE, \"No threads for storage transfer allowed.\");\r\n            return false;\r\n        }\r\n\r\n        // make sure command exists\r\n        try {\r\n            Process pro = Runtime.getRuntime().exec(\"which \" + storageAccessCmd);\r\n            int exitValue = pro.waitFor();\r\n            if (exitValue != 0) {\r\n                logger.log(Level.SEVERE, \"Unable to find executable \" + this.storageAccessCmd);\r\n                return false;\r\n            }\r\n        } catch (Exception e) {\r\n            logger.log(Level.SEVERE, \"Unable to execute \\\"which \" + this.storageAccessCmd + \"\\\"\");\r\n            return false;\r\n        }\r\n\r\n        // print out read attributes\r\n        if (this.verbose > 0) {\r\n            System.out.println(\"Storage access configured with\\n\" + \"siteStorageID = \" + this.siteStorageID + \"\\n\" + \"storageRoot = \" + this.storageRoot + \"\\n\" + \"storageAccessCmd = \" + this.storageAccessCmd + \"\\n\"\r\n                    + \"storageCmdOptions = \" + this.storageCmdOptions + \"\\n\" + \"storageAccessPoint = \" + this.storageAccessPoint + \"\\n\" + \"localFilePrefix = \" + this.localFilePrefix + \"\\n\" + \"localFileDir = \"\r\n                    + this.localFileDir + \"\\n\" + \"nThreads = \" + this.nThreads);\r\n        }\r\n\r\n        // exit\r\n        return true;\r\n    }// end init()\r\n\r\n}// end of class MassStorage\r\n"
  },
  {
    "path": "src/lia/util/net/common/MonitoringUtils.java",
    "content": "package lia.util.net.common;\n\nimport lia.util.net.copy.FDT;\nimport lia.util.net.copy.FDTSession;\nimport org.opentsdb.client.ExpectResponse;\nimport org.opentsdb.client.HttpClient;\nimport org.opentsdb.client.builder.Metric;\nimport org.opentsdb.client.builder.MetricBuilder;\nimport org.opentsdb.client.response.Response;\n\nimport java.io.IOException;\nimport java.net.*;\nimport java.util.Enumeration;\nimport java.util.Iterator;\nimport java.util.Vector;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Raimondas Sirvinskas\n * @version 1.0\n */\npublic class MonitoringUtils {\n\n    private static Logger logger = Logger.getLogger(MonitoringUtils.class.getName());\n\n    private Config config;\n    private HttpClient client;\n    private String hostName;\n    private FDTSession session;\n\n    public MonitoringUtils(Config config, FDTSession session) {\n        this.session = session;\n        this.config = config;\n        this.client = config.getOpenTSDBMonitorClient();\n        this.hostName = getHostName();\n    }\n\n    public MonitoringUtils(Config config) {\n        this.config = config;\n        this.client = config.getOpenTSDBMonitorClient();\n        this.hostName = getHostName();\n    }\n\n    public void monitorStart(long timeRequested, String clusterName) {\n        MetricBuilder builder = MetricBuilder.getInstance();\n        Metric metric = builder.addMetric(\"fdt.transferstatus.timeStarted\")\n                .setDataPoint(timeRequested, timeRequested);\n        addTags(metric, clusterName, null);\n        monitorStartSession(builder, timeRequested, clusterName);\n        sendMetricsToServer(builder);\n    }\n\n    public void monitorFinish(long timeRequested, String clusterName) {\n        MetricBuilder builder = MetricBuilder.getInstance();\n        Metric metric = builder.addMetric(\"fdt.transferstatus.timeFinished\")\n                .setDataPoint(timeRequested, timeRequested);\n        addTags(metric, clusterName, null);\n        monitorFinishSession(builder, timeRequested, clusterName);\n        sendMetricsToServer(builder);\n    }\n\n    private synchronized void sendMetricsToServer(MetricBuilder builder) {\n        if (builder.getMetrics().size() > 0) {\n            if (logger.isLoggable(Level.FINE)) {\n                Iterator iterator = builder.getMetrics().listIterator();\n                while (iterator.hasNext()) {\n                    try {\n                        Metric metric = (Metric) iterator.next();\n                        logger.log(Level.FINE, \"metric    \" + metric.getName() + \" \" + metric.stringValue());\n                        logger.log(Level.FINE, \"metric tag names: \" + builder.getMetrics().listIterator().next().getTags().keySet().toString());\n                        logger.log(Level.FINE, \"metric tag values: \" + builder.getMetrics().listIterator().next().getTags().values().toString());\n                    } catch (Exception e) {\n                        //do nothing\n                    }\n                }\n            }\n            try {\n                if (client != null) {\n                    Response response = client.pushMetrics(builder, ExpectResponse.SUMMARY);\n                    logger.log(Level.FINE, \"Response from OpenTSDB server: \" + response.toString());\n                }\n            } catch (IOException e) {\n                logger.log(Level.WARNING, \"Failed to send metrics to OpenTSDB server\", e);\n            }\n        }\n\n    }\n\n    private void monitorStartSession(MetricBuilder builder, long timeStarted, String clusterName) {\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"debugLevel\", Level.parse(config.getLogLevel()).intValue());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"bio\", config.isBlocking() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"notmp\", config.isNoTmpFlagSet() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nolock\", config.isNoLockFlagSet() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nolocks\", config.getConfigMap().get(\"-nolocks\") != null ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nettest\", config.isNetTest() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"bs\", config.getByteBufferSize());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"P\", config.getSockNum());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"ss\", config.getSockBufSize());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"limit\", config.getRateLimit());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"iof\", config.getRetryIOCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"rCount\", config.getReadersCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"wCount\", config.getWritersCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"pCount\", config.getMaxPartitionCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"sourcePort\", config.getPort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"destPort\", session.getRemotePort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"transferPort\", session.getTransferPort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"totalBytes\", session.getTotalBytes());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"status\", 1);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"recursive\", config.isRecursive() ? 1 : 0);\n    }\n\n    private void monitorFinishSession(MetricBuilder builder, long timeStarted, String clusterName) {\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"debugLevel\", Level.parse(config.getLogLevel()).intValue());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"bio\", config.isBlocking() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"notmp\", config.isNoTmpFlagSet() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nolock\", config.isNoLockFlagSet() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nolocks\", config.getConfigMap().get(\"-nolocks\") != null ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"nettest\", config.isNetTest() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"bs\", config.getByteBufferSize());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"P\", config.getSockNum());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"ss\", config.getSockBufSize());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"limit\", config.getRateLimit());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"iof\", config.getRetryIOCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"rCount\", config.getReadersCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"wCount\", config.getWritersCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"pCount\", config.getMaxPartitionCount());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"sourcePort\", config.getPort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"destPort\", session.getRemotePort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"transferPort\", session.getTransferPort());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"totalBytes\", session.getTotalBytes());\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"status\", 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"recursive\", config.isRecursive() ? 1 : 0);\n        monitorStartConfiguration(builder, timeStarted, clusterName, \"exitStatus\", session.getCurrentStatus());\n    }\n\n    public void monitorStartConfiguration(MetricBuilder builder, long timeStarted, String clusterName, String configParam, long configValue) {\n        Metric metric = builder.addMetric(\"fdt.transferstatus.\" + configParam)\n                .setDataPoint(timeStarted, configValue);\n        addTags(metric, clusterName, null);\n    }\n\n    private void addTags(Metric metric, String clusterName, String destIP) {\n        metric.addTag(\"fdthost\", hostName != null ? hostName : \"none\")\n                .addTag(\"fdtversion\", FDT.FDT_FULL_VERSION)\n                .addTag(\"fdtsourceIP\", getHostIP())\n                .addTag(\"fdtdestIP\", destIP == null ? session != null ? session.getRemoteAddress().getHostAddress() : \"0.0.0.0\" : destIP)\n                .addTag(\"fdtclusterName\", clusterName)\n                .addTag(\"fdtcustomFDTTag\", config.getFDTTag());\n    }\n\n    public synchronized void shareMetrics(String clusterName, String nodeName, Vector paramNames, Vector paramValues) {\n        final String hostName = getHostName();\n\n        MetricBuilder builder = MetricBuilder.getInstance();\n        Iterator nameIterator = paramNames.iterator();\n        Iterator valueIterator = paramValues.iterator();\n        String[] node = nodeName.split(\":\");\n\n        while (nameIterator.hasNext() && valueIterator.hasNext() && paramNames.size() == paramValues.size()) {\n            try {\n                Object nameObject = nameIterator.next();\n                Object valueObject = valueIterator.next();\n                double value = Double.valueOf(valueObject.toString());\n                Metric metric = builder.addMetric(\"fdt.transferstatus.\" + String.valueOf(nameObject))\n                        .setDataPoint(System.currentTimeMillis(), value);\n                addTags(metric, clusterName, node[0]);\n\n                logger.log(Level.FINE, \"metric    \" + metric.getName() + \" \" + metric.stringValue());\n                logger.log(Level.FINE, \"metric tag names: \" + metric.getTags().keySet().toString());\n                logger.log(Level.FINE, \"metric tag values: \" + metric.getTags().values().toString());\n            } catch (Exception e) {\n                logger.log(Level.FINEST, \"Failed to parse metric value \", e);\n            }\n        }\n\n        sendMetricsToServer(builder);\n    }\n\n    private String getHostName() {\n        String host = null;\n        try {\n            InetAddress localhost = InetAddress.getLocalHost();\n            host = localhost.getHostName();\n        } catch (UnknownHostException e) {\n            e.printStackTrace();\n        }\n        if (host == null) {\n            host = System.getenv(\"HOSTNAME\");\n        }\n        return host;\n    }\n\n    private String getHostIP() {\n        String ip = null;\n        try {\n            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();\n            while (interfaces.hasMoreElements()) {\n                NetworkInterface iface = interfaces.nextElement();\n                if (iface.isLoopback() || !iface.isUp())\n                    continue;\n\n                Enumeration<InetAddress> addresses = iface.getInetAddresses();\n                while (addresses.hasMoreElements()) {\n                    InetAddress addr = addresses.nextElement();\n                    if (addr instanceof Inet6Address) continue;\n                    ip = addr.getHostAddress();\n                }\n            }\n        } catch (SocketException e) {\n            throw new RuntimeException(e);\n        }\n        return ip != null ? ip : \"0.0.0.0\";\n    }\n\n    public void monitorEndStats(boolean finishStatus, long totalBytes, long utilBytes, long startTimeMillis, long endTime, long period, String clusterName) {\n        MetricBuilder builder = MetricBuilder.getInstance();\n        monitorStartConfiguration(builder, endTime, clusterName, \"destPort\", session.getRemotePort());\n        monitorStartConfiguration(builder, endTime, clusterName, \"transferTime\", period);\n        monitorStartConfiguration(builder, endTime, clusterName, \"totalFileBytes\", totalBytes);\n        monitorStartConfiguration(builder, endTime, clusterName, \"totalNetworkBytes\", utilBytes);\n        monitorStartConfiguration(builder, endTime, clusterName, \"finishStatus\", finishStatus ? 1 : 0);\n        monitorStartConfiguration(builder, endTime, clusterName, \"startTime\", startTimeMillis);\n        monitorStartConfiguration(builder, endTime, clusterName, \"endTime\", endTime);\n        sendMetricsToServer(builder);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/NetMatcher.java",
    "content": "/*\n * $Id$\n */\n\n/***********************************************************************\n * Copyright (c) 2000-2004 The Apache Software Foundation.             *\n * All rights reserved.                                                *\n * ------------------------------------------------------------------- *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you *\n * may not use this file except in compliance with the License. You    *\n * may obtain a copy of the License at:                                *\n *                                                                     *\n *     http://www.apache.org/licenses/LICENSE-2.0                      *\n *                                                                     *\n * Unless required by applicable law or agreed to in writing, software *\n * distributed under the License is distributed on an \"AS IS\" BASIS,   *\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *\n * implied.  See the License for the specific language governing       *\n * permissions and limitations under the License.                      *\n ***********************************************************************/\n\n/*\n * \n * Modified for compatibility with Java 1.5 - Corina Stratan, March 2005.\n * FIXME - this class MUST be rewritten ... it does not accomodate IPv6\n *    \n */\npackage lia.util.net.common;\n\nimport java.net.InetAddress;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Iterator;\n\npublic class NetMatcher {\n\n    private ArrayList<InetNetwork> networks;\n\n    public NetMatcher() {\n    }\n\n    public NetMatcher(final String[] nets) {\n        initInetNetworks(nets);\n    }\n\n    public NetMatcher(final Collection nets) {\n        initInetNetworks(nets);\n    }\n\n    public void initInetNetworks(final Collection<String> nets) {\n        networks = new ArrayList<InetNetwork>();\n        for (final String netName : nets)\n            try {\n                InetNetwork net = InetNetwork.getFromString(netName);\n                if (!networks.contains(net)) networks.add(net);\n            } catch (java.net.UnknownHostException uhe) {\n                log(\"Cannot resolve address: \" + uhe.getMessage());\n            }\n        networks.trimToSize();\n    }\n\n    public void initInetNetworks(final String[] nets) {\n        networks = new ArrayList<InetNetwork>();\n        for (int i = 0; i < nets.length; i++)\n            try {\n                InetNetwork net = InetNetwork.getFromString(nets[i]);\n                if (!networks.contains(net)) networks.add(net);\n            } catch (java.net.UnknownHostException uhe) {\n                log(\"Cannot resolve address: \" + uhe.getMessage());\n            }\n        networks.trimToSize();\n    }\n\n    public boolean matchInetNetwork(final String hostIP) {\n        InetAddress ip = null;\n\n        try {\n            ip = InetAddress.getByName(hostIP);\n        } catch (java.net.UnknownHostException uhe) {\n            log(\"Cannot resolve address for \" + hostIP + \": \" + uhe.getMessage());\n        }\n\n        boolean sameNet = false;\n\n        if (ip != null) for (Iterator<InetNetwork> iter = networks.iterator(); (!sameNet) && iter.hasNext(); ) {\n            InetNetwork network = iter.next();\n            sameNet = network.contains(ip);\n        }\n        return sameNet;\n    }\n\n    public boolean matchInetNetwork(final InetAddress ip) {\n        boolean sameNet = false;\n\n        for (Iterator<InetNetwork> iter = networks.iterator(); (!sameNet) && iter.hasNext(); ) {\n            InetNetwork network = iter.next();\n            sameNet = network.contains(ip);\n        }\n        return sameNet;\n    }\n\n    public String toString() {\n        return networks.toString();\n    }\n\n    protected void log(String s) {\n    }\n}\n\nclass InetNetwork {\n\n    /*\n     * Implements network masking, and is compatible with RFC 1518 and\n     * RFC 1519, which describe CIDR: Classless Inter-Domain Routing.\n     */\n\n    private static java.lang.reflect.Method getByAddress = null;\n\n    static {\n        try {\n            Class inetAddressClass = Class.forName(\"java.net.InetAddress\");\n            Class[] parameterTypes = {byte[].class};\n            getByAddress = inetAddressClass.getMethod(\"getByAddress\", parameterTypes);\n        } catch (Exception e) {\n            getByAddress = null;\n        }\n    }\n\n    private InetAddress network;\n    private InetAddress netmask;\n\n    public InetNetwork(InetAddress ip, InetAddress netmask) {\n        network = maskIP(ip, netmask);\n        this.netmask = netmask;\n    }\n\n    public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException {\n        if (netspec.endsWith(\"*\"))\n            netspec = normalizeFromAsterisk(netspec);\n        else {\n            int iSlash = netspec.indexOf('/');\n            if (iSlash == -1)\n                netspec += \"/255.255.255.255\";\n            else if (netspec.indexOf('.', iSlash) == -1) netspec = normalizeFromCIDR(netspec);\n        }\n\n        return new InetNetwork(InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))), InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1)));\n    }\n\n    public static final InetAddress maskIP(final byte[] ip, final byte[] mask) {\n        try {\n            return getByAddress(new byte[]{(byte) (mask[0] & ip[0]), (byte) (mask[1] & ip[1]), (byte) (mask[2] & ip[2]), (byte) (mask[3] & ip[3])});\n        } catch (final Exception ignored) {\n        }\n        return null;\n    }\n\n    public static InetAddress maskIP(final InetAddress ip, final InetAddress mask) {\n        return maskIP(ip.getAddress(), mask.getAddress());\n    }\n\n    /*\n     * This converts from an uncommon \"wildcard\" CIDR format\n     * to \"address + mask\" format:\n     *\n     *   *               =>  000.000.000.0/000.000.000.0\n     *   xxx.*           =>  xxx.000.000.0/255.000.000.0\n     *   xxx.xxx.*       =>  xxx.xxx.000.0/255.255.000.0\n     *   xxx.xxx.xxx.*   =>  xxx.xxx.xxx.0/255.255.255.0\n     */\n    static private String normalizeFromAsterisk(final String netspec) {\n        String[] masks = {\"0.0.0.0/0.0.0.0\", \"0.0.0/255.0.0.0\", \"0.0/255.255.0.0\", \"0/255.255.255.0\"};\n        char[] srcb = netspec.toCharArray();\n        int octets = 0;\n        for (int i = 1; i < netspec.length(); i++) {\n            if (srcb[i] == '.') octets++;\n        }\n        return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() - 1).concat(masks[octets]);\n    }\n\n    /*\n     * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)\n     * This converts from \"prefix + prefix-length\" format to\n     * \"address + mask\" format, e.g. from xxx.xxx.xxx.xxx/yy\n     * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.\n     */\n    static private String normalizeFromCIDR(final String netspec) {\n        final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/') + 1));\n        final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits) - 1);\n\n        return netspec.substring(0, netspec.indexOf('/') + 1) + Integer.toString(mask >> 24 & 0xFF, 10) + \".\" + Integer.toString(mask >> 16 & 0xFF, 10) + \".\" + Integer.toString(mask >> 8 & 0xFF, 10) + \".\" + Integer.toString(mask >> 0 & 0xFF, 10);\n    }\n\n    private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException {\n        InetAddress addr = null;\n        if (getByAddress != null) try {\n            addr = (InetAddress) getByAddress.invoke(null, new Object[]{ip});\n        } catch (IllegalAccessException e) {\n        } catch (java.lang.reflect.InvocationTargetException e) {\n        }\n\n        if (addr == null) {\n            addr = InetAddress.getByName(Integer.toString(ip[0] & 0xFF, 10) + \".\" + Integer.toString(ip[1] & 0xFF, 10) + \".\" + Integer.toString(ip[2] & 0xFF, 10) + \".\" + Integer.toString(ip[3] & 0xFF, 10));\n        }\n        return addr;\n    }\n\n    //test\n    public static void main(String[] args) {\n        NetMatcher nm = new NetMatcher();\n        nm.initInetNetworks(new String[]{\"192.168.0.0/24\"});\n        System.out.println(nm.matchInetNetwork(\"192.168.0.2\"));\n\n    }\n\n    public boolean contains(final String name) throws java.net.UnknownHostException {\n        return network.equals(maskIP(InetAddress.getByName(name), netmask));\n    }\n\n    public boolean contains(final InetAddress ip) {\n        return network.equals(maskIP(ip, netmask));\n    }\n\n    public String toString() {\n        return network.getHostAddress() + \"/\" + netmask.getHostAddress();\n    }\n\n    public int hashCode() {\n        return maskIP(network, netmask).hashCode();\n    }\n\n    public boolean equals(Object obj) {\n        return (obj != null) && (obj instanceof InetNetwork) && ((((InetNetwork) obj).network.equals(network)) && (((InetNetwork) obj).netmask.equals(netmask)));\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/NetloggerRecord.java",
    "content": "package lia.util.net.common;\n\nimport java.net.InetAddress;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * @author nlmills@g.clemson.edu\n */\npublic class NetloggerRecord {\n    /**\n     * the size of the data block read from the disk and posted to the network\n     */\n    private int block;\n    /**\n     * tcp buffer size (if 0 system defaults were used)\n     */\n    private int buffer;\n    /**\n     * the FTP rfc959 completion code of the transfer\n     */\n    private String code = \"429\";  // = \"Connection closed; transfer aborted.\"\n    /**\n     * time the transfer completed\n     */\n    private Date completed = new Date();\n    /**\n     * the destination host\n     */\n    private InetAddress destination = Utils.getLoopbackAddress();\n    /**\n     * hostname of the server\n     */\n    private InetAddress host = Utils.getLoopbackAddress();\n    /**\n     * the total number of bytes transferred\n     */\n    private long nbytes;\n    /**\n     * time the transfer started\n     */\n    private Date start = completed;\n    /**\n     * the number of parallel TCP streams used in the transfer\n     */\n    private int streams;\n    /**\n     * the transfer type (RETR or STOR)\n     */\n    private String type = \"RETR\";\n\n    public static String toULMDate(Date date) {\n        // year month day hour minute second . millisecond\n        SimpleDateFormat ulmFormat = new SimpleDateFormat(\"yyyyMMddHHmmss.SSS\");\n        // Date only has millisecond precision, so tack on zeros for microseconds\n        String ulmDate = ulmFormat.format(date) + \"000\";\n\n        return ulmDate;\n    }\n\n    public int getBuffer() {\n        return buffer;\n    }\n\n    public void setBuffer(int buffer) {\n        this.buffer = buffer;\n    }\n\n    public int getBlock() {\n        return block;\n    }\n\n    public void setBlock(int block) {\n        this.block = block;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public void setCode(String code) {\n        this.code = code;\n    }\n\n    public Date getCompleted() {\n        return completed;\n    }\n\n    public void setCompleted(Date completed) {\n        this.completed = completed;\n    }\n\n    public InetAddress getDestination() {\n        return destination;\n    }\n\n    public void setDestination(InetAddress destination) {\n        this.destination = destination;\n    }\n\n    public InetAddress getHost() {\n        return host;\n    }\n\n    public void setHost(InetAddress host) {\n        this.host = host;\n    }\n\n    public long getNbytes() {\n        return nbytes;\n    }\n\n    public void setNbytes(long nbytes) {\n        this.nbytes = nbytes;\n    }\n\n    public Date getStart() {\n        return start;\n    }\n\n    public void setStart(Date start) {\n        this.start = start;\n    }\n\n    public int getStreams() {\n        return streams;\n    }\n\n    public void setStreams(int streams) {\n        this.streams = streams;\n    }\n\n    public String getType() {\n        return type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public String toULMString() {\n        String ulm = Utils.joinString(\" \",\n                \"DATE=\" + toULMDate(completed),\n                \"HOST=\" + host.getHostName(),\n                \"PROG=fdt\",\n                //XXX what about NL.EVNT=FTP_INFO?\n                \"START=\" + toULMDate(start),\n                \"BUFFER=\" + buffer,\n                \"BLOCK=\" + block,\n                \"NBYTES=\" + nbytes,\n                \"STREAMS=\" + streams,\n                \"DEST=[\" + destination.getHostAddress() + \"]\",\n                \"TYPE=\" + type,\n                \"CODE=\" + code);\n\n        return ulm;\n    }\n\n    @Override\n    public String toString() {\n        return toULMString();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/SSHControlStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport ch.ethz.ssh2.Connection;\nimport ch.ethz.ssh2.InteractiveCallback;\nimport ch.ethz.ssh2.Session;\nimport ch.ethz.ssh2.StreamGobbler;\nimport ch.ethz.ssh2.util.PasswordReader;\n\nimport java.io.*;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Adrian Muraru\n */\npublic class SSHControlStream implements ControlStream {\n\n    static final String knownHostPath = System.getProperty(\"user.home\") + \"/.ssh/known_hosts\";\n    static final String idDSAPath = System.getProperty(\"user.home\") + \"/.ssh/id_dsa.fdt\";\n    static final String idRSAPath = System.getProperty(\"user.home\") + \"/.ssh/id_rsa.fdt\";\n    private static final Logger logger = Logger.getLogger(SSHControlStream.class.getName());\n    // configuration parameters\n    private final String hostname;\n    private final String username;\n    private final int port;\n\n    /**\n     * the SSH connection & session\n     */\n    private Connection conn;\n    private Session sess;\n    private String cmd;\n    private String customShell;\n\n    /**\n     * Creates a new SSH control connection on the default ssh port.\n     * <p>\n     * Same as {@link #SSHControlStream(String, String, int) SSHControlStream(hostname, username, 22)}\n     *\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public SSHControlStream(String hostname, String username) {\n        this(hostname, username, 22);\n    }\n\n    /**\n     * Creates a new SSH control connection on the specified remote sshd port\n     *\n     * @param port:     remote sshd port\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public SSHControlStream(String hostname, String username, int port) {\n        this.hostname = hostname;\n        this.username = username;\n        this.port = port;\n    }\n\n    // TEST\n    public static void main(String[] args) throws IOException {\n        ControlStream cs = new SSHControlStream(args[0], args[1]);\n        cs.startProgram(args[2], args[3]);\n\n        /* read stdout */\n        InputStream stdout = new StreamGobbler(cs.getProgramStdOut());\n        BufferedReader br = new BufferedReader(new InputStreamReader(stdout));\n        while (true) {\n            String line = br.readLine();\n            if (line == null) {\n                break;\n            }\n            System.out.println(line);\n        }\n        System.out.println(\"ExitCode:\" + cs.getExitCode());\n        cs.close();\n    }\n\n    public void connect() throws IOException {\n        this.conn = new Connection(hostname, port);\n        conn.connect();\n\n        /*\n         * AUTHENTICATION PHASE\n         */\n\n        boolean enableKeyboardInteractive = true;\n        boolean enableDSA = true;\n        boolean enableRSA = true;\n        boolean enableKEY = true;\n\n        String lastError = null;\n        int passwordRetry = 0;\n\n        //\n        //TODO - Add more logging ... in case smth does not work with the keys\n        //\n        final String configSshKeyPath = Config.getInstance().getSshKeyPath();\n        File sshKeyPath = null;\n        if (configSshKeyPath != null) {\n            try {\n                sshKeyPath = new File(configSshKeyPath);\n                if (!sshKeyPath.exists() || !sshKeyPath.canRead()) {\n                    sshKeyPath = null;\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" [ SSHControlStream ] Unable to check configSshKeyPath\", t);\n            }\n        }\n\n        if (sshKeyPath == null) {\n            enableKEY = false;\n        }\n\n        while (true) {\n            if ((enableKEY || enableDSA || enableRSA) && conn.isAuthMethodAvailable(username, \"publickey\")) {\n\n                if (enableKEY && sshKeyPath != null) {\n                    boolean res = false;\n                    String password = getPassword(\"\\n [\" + username + \"@\" + hostname + \"] [Public key authentication] Enter password for SSH private key[\" + configSshKeyPath + \"]: \");\n                    try {\n                        res = conn.authenticateWithPublicKey(username, sshKeyPath, password);\n                    } catch (Exception e) {\n                        res = false;\n                    }\n                    if (res == true) {\n                        break;\n                    }\n\n                    enableKEY = false;\n                }\n\n                if (enableDSA) {\n                    File key = new File(idDSAPath);\n\n                    if (key.exists() && key.canRead()) {\n                        boolean res = false;\n                        String password = getPassword(\"\\n [\" + username + \"@\" + hostname + \"] [Public key authentication] Enter password for DSA private key[\" + idDSAPath + \"]: \");\n                        try {\n                            res = conn.authenticateWithPublicKey(username, key, password);\n                        } catch (Exception e) {\n                            res = false;\n                        }\n                        if (res == true) {\n                            break;\n                        }\n                        lastError = \"DSA authentication failed.\";\n                    }\n                    enableDSA = false; // do not try again\n\n                }\n\n                if (enableRSA) {\n                    File key = new File(idRSAPath);\n\n                    if (key.exists() && key.exists()) {\n                        boolean res = false;\n                        String password = getPassword(\"\\n[\" + username + \"@\" + hostname + \"] [Public key authentication] Enter password for RSA private key[\" + idRSAPath + \"]: \");\n                        try {\n                            res = conn.authenticateWithPublicKey(username, key, password);\n                        } catch (Exception e) {\n                            res = false;\n                        }\n                        if (res == true) {\n                            break;\n                        }\n                        lastError = \"RSA authentication failed.\";\n                    }\n                    enableRSA = false; // do not try again\n\n                }\n\n                continue;\n            }\n\n            if (enableKeyboardInteractive && conn.isAuthMethodAvailable(username, \"keyboard-interactive\")) {\n                InteractiveLogic il = new InteractiveLogic(lastError, \"\\n[\" + username + \"@\" + hostname + \"]\");\n\n                boolean res = false;\n                try {\n                    res = conn.authenticateWithKeyboardInteractive(username, il);\n                } catch (Exception e) {\n                    res = false;\n                    lastError = \"Keyboard-interactive auth failed. \" + e.getMessage();\n                }\n\n                if (res == true) {\n                    break;\n                }\n                if (il.getPromptCount() == 0) {\n                    // aha. the server announced that it supports \"keyboard-interactive\", but when\n                    // we asked for it, it just denied the request without sending us any prompt.\n                    // That happens with some server versions/configurations.\n                    // We just disable the \"keyboard-interactive\" method and notify the user.\n\n                    lastError = \"Keyboard-interactive does not work.\";\n\n                    enableKeyboardInteractive = false; // do not try this again\n\n                } else {\n                    lastError = \"Keyboard-interactive auth failed.\"; // try again, if possible\n\n                }\n\n                continue;\n            }\n\n            if (conn.isAuthMethodAvailable(username, \"password\")) {\n                boolean res = false;\n\n                String password = getPassword(\"\\n[\" + username + \"@\" + hostname + \"] [Password Authentication] Enter password: \");\n                if (password == null || password.length() == 0) {\n                    res = false;\n                } else {\n                    res = conn.authenticateWithPassword(username, password);\n                }\n                if (res == true) {\n                    break;\n                }\n                lastError = \"Password authentication failed.\"; // try again, if possible\n\n                if (++passwordRetry == 3) {\n                    throw new IOException(\"Too many tries. Give up.\");\n                }\n                continue;\n            }\n\n            throw new IOException(\"No supported authentication methods available.\");\n        }\n        /*\n         * AUTHENTICATION OK.\n         */\n        this.sess = this.conn.openSession();\n        this.sess.requestPTY(\"javash\", 0, 0, 0, 0, null);\n    }\n\n    public String getPassword(String message) throws IOException {\n        return PasswordReader.readPassword(message);\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#startProgram(java.lang.String)\n     */\n    public void startProgram(String cmd, String customShell) throws IOException {\n        this.cmd = customShell + \" --login -c '\" + cmd + \" 2>&1'\";\n        this.sess.execCommand(this.cmd);\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#getProgramStdOut()\n     */\n    public InputStream getProgramStdOut() {\n        return this.sess.getStdout();\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#getProgramStdErr()\n     */\n    public InputStream getProgramStdErr() {\n        return this.sess.getStderr();\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String, boolean, boolean)\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF, boolean grabRemainingLog) throws IOException {\n        /* read stdout */\n        // InputStream stdout = new StreamGobbler(getProgramStdOut());\n        BufferedReader br = new BufferedReader(new InputStreamReader(getProgramStdOut()));\n        final String outputPrefix = \"[\" + this.conn.getHostname() + \"]$ \";\n        while (true) {\n            String line = br.readLine();\n            if (line == null) {\n                if (allowEOF) {\n                    return;\n                    //else\n                }\n                throw new IOException(\"[\" + this.cmd + \"] exited. No control message received]\");\n            }\n            System.err.println(outputPrefix + line);\n            if (line.trim().equalsIgnoreCase(expect)) {\n                LogWriter lw = grabRemainingLog ? new LogWriter(br, \"fdt_\" + this.conn.getHostname() + \".log\") : new LogWriter(br);\n                lw.setDaemon(true);\n                lw.start();\n                return;\n            }\n        }\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String, boolean)\n     */\n    public void waitForControlMessage(String expect, boolean allowEOF) throws IOException {\n        this.waitForControlMessage(expect, allowEOF, false);\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#waitForControlMessage(java.lang.String)\n     */\n    public void waitForControlMessage(String expect) throws IOException {\n        this.waitForControlMessage(expect, false, true);\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#saveStdErr()\n     */\n    public void saveStdErr() throws IOException {\n        BufferedReader br = new BufferedReader(new InputStreamReader(getProgramStdErr()));\n        LogWriter lw = new LogWriter(br, \"fdt_\" + this.conn.getHostname() + \".err\");\n        lw.setDaemon(true);\n        lw.start();\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#getExitCode()\n     */\n    public int getExitCode() {\n        return this.sess.getExitStatus();\n    }\n\n    /* (non-Javadoc)\n     * @see lia.util.net.common.ControlStream#close()\n     */\n    public void close() {\n        if (this.sess != null) {\n            this.sess.close();\n        }\n        if (this.conn != null) {\n            this.conn.close();\n        }\n    }\n\n    /**\n     * asynch write in a local log file of the remote stderr stream\n     */\n    static class LogWriter extends Thread {\n\n        BufferedReader br;\n        String logFile;\n\n        public LogWriter(BufferedReader br) {\n            this.br = br;\n            this.logFile = null;\n        }\n\n        public LogWriter(BufferedReader br, String fileName) {\n            this.br = br;\n            this.logFile = fileName;\n        }\n\n        public void run() {\n            BufferedWriter out = null;\n            try {\n                if (this.logFile != null) {\n                    out = new BufferedWriter(new FileWriter(logFile, false));\n                    final Date date = new Date();\n                    out.write(\"==============\" + new SimpleDateFormat(\"E, dd MMM yyyy HH:mm:ss Z\").format(date) + \"================\\n\");\n                }\n                while (true) {\n                    String line = br.readLine();\n\n                    if (line == null) {\n                        if (out != null) {\n                            out.close();\n                        }\n                        return;\n                    }\n                    if (out != null) {\n                        out.write(line + \"\\n\");\n                        out.flush();\n                    }\n                }\n            } catch (IOException e) {\n                System.err.println(\"Cannot write remote log:\" + logFile);\n                try {\n                    if (out != null) {\n                        out.close();\n                    }\n                } catch (IOException e1) {\n                }\n                return;\n            }\n        }\n    }\n\n    /**\n     * The logic that one has to implement if \"keyboard-interactive\" autentication shall be supported.\n     */\n    class InteractiveLogic implements InteractiveCallback {\n\n        int promptCount = 0;\n        String lastError;\n        String prefix;\n\n        public InteractiveLogic(String lastError, String prefix) {\n            this.lastError = lastError;\n            this.prefix = prefix;\n        }\n\n        /* the callback may be invoked several times, depending on how many questions-sets the server sends */\n        public String[] replyToChallenge(String name, String instruction, int numPrompts, String[] prompt, boolean[] echo) throws IOException {\n            String[] result = new String[numPrompts];\n\n            for (int i = 0; i < numPrompts; i++) {\n                /* Often, servers just send empty strings for \"name\" and \"instruction\" */\n\n                if (lastError != null) {\n                    /* show lastError only once */\n                    lastError = null;\n                }\n\n                StringBuilder sContent = new StringBuilder();\n                /*\t\t\tif (lastError != null && lastError.trim().length() > 0)\n                sContent.append(lastError).append('\\n');*/\n                if (name != null && name.trim().length() > 0) {\n                    sContent.append(name).append(' ');\n                }\n                if (instruction != null && instruction.trim().length() > 0) {\n                    sContent.append(instruction).append('\\n');\n                }\n                sContent.append(prefix).append(\"[Keyboard Interactive Authentication] \").append(prompt[i]);\n\n                String userResponse = getPassword(sContent.toString());\n\n                if (userResponse == null) {\n                    throw new IOException(\"Login aborted by user\");\n                }\n                result[i] = userResponse;\n                promptCount++;\n            }\n\n            return result;\n        }\n\n        /*\n         * We maintain a prompt counter - this enables the detection of situations where the ssh server is signaling \"authentication failed\" even though it did not send a single\n         * prompt.\n         */\n        public int getPromptCount() {\n            return promptCount;\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/StoragePathDecoder.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\n/**\n * @author Ilya Narsky\n */\npublic class StoragePathDecoder {\n\n    private String storageType;\n    private String siteStorageID;\n    private String storageRoot;\n    private String pathToFileFromRoot;\n\n    public StoragePathDecoder(String path,\n                              String siteStorageID,\n                              String storageRoot) {\n        if (siteStorageID != null) this.siteStorageID = siteStorageID;\n        if (storageRoot != null) this.storageRoot = storageRoot;\n        if (path != null) this.decode(path);\n    }\n\n    public String storageType() {\n        return this.storageType;\n    }\n\n    public String siteStorageID() {\n        return this.siteStorageID;\n    }\n\n    public String storageRoot() {\n        return this.storageRoot;\n    }\n\n    public String pathToFileFromRoot() {\n        return this.pathToFileFromRoot;\n    }\n\n    public boolean hasStorageInfo() {\n        return (this.storageType != null && this.storageType.length() != 0);\n    }\n\n\n    private void decode(String path) {\n        // remove spaces\n        String temp = path.trim();\n\n        // the first part up to \"_//\" is treated as storage\n        if (temp.contains(\"_//\")) {\n            String[] splitByStorage = temp.split(\"_//\", 2);\n            this.storageType = splitByStorage[0];\n            temp = splitByStorage[1];\n        }\n\n        // remove the site name from the string\n        temp = temp.replaceFirst(this.siteStorageID, \"\");\n\n        // remove the storage root from the string\n        temp = temp.replaceFirst(this.storageRoot, \"\");\n\n        // the rest of it is supposed to be the full path to file\n        this.pathToFileFromRoot = temp;\n    }// end of decode()\n\n}\n\n"
  },
  {
    "path": "src/lia/util/net/common/SystemLoadMonitor.java",
    "content": "package lia.util.net.common;\n\nimport oshi.SystemInfo;\nimport oshi.hardware.CentralProcessor;\nimport oshi.software.os.OperatingSystem;\n\npublic class SystemLoadMonitor implements Runnable {\n\n    private static final long MONITOR_INTERVAL_MS = 1000;\n\n    private volatile double cpuLoad = 0.0;\n    private volatile double[] perCoreLoads = new double[0];\n    private volatile double[] systemLoadAverage = new double[3]; // 1, 5, 15-minute averages\n    private volatile long contextSwitches = 0;\n\n    private final SystemInfo systemInfo;\n    private final CentralProcessor processor;\n    private final OperatingSystem os;\n    private Thread monitorThread;\n\n    private long[] prevTicks;\n    private long[][] prevProcTicks;\n    private long prevContextSwitches = 0;\n\n    private static SystemLoadMonitor instance = new SystemLoadMonitor();\n\n    private SystemLoadMonitor() {\n        systemInfo = new SystemInfo();\n        processor = systemInfo.getHardware().getProcessor();\n        os = systemInfo.getOperatingSystem();\n        prevTicks = processor.getSystemCpuLoadTicks();\n        prevProcTicks = processor.getProcessorCpuLoadTicks();\n        prevContextSwitches = getRawContextSwitches();\n        startMonitoring();\n    }\n\n    public static SystemLoadMonitor getInstance() {\n        return instance;\n    }\n\n    private void startMonitoring() {\n        monitorThread = new Thread(this, \"SystemLoadMonitor\");\n        monitorThread.setDaemon(true);\n        monitorThread.start();\n    }\n\n    @Override\n    public void run() {\n        while (true) {\n            cpuLoad = calculateCpuLoad();\n            perCoreLoads = calculatePerCoreCpuLoad();\n            systemLoadAverage = getSystemLoadAverage();\n            contextSwitches = calculateContextSwitches();\n\n            try {\n                Thread.sleep(MONITOR_INTERVAL_MS);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                break;\n            }\n        }\n    }\n\n    private double calculateCpuLoad() {\n        double load = processor.getSystemCpuLoadBetweenTicks(prevTicks);\n        prevTicks = processor.getSystemCpuLoadTicks();\n        return load; // Value between 0.0 and 1.0\n    }\n\n    private double[] calculatePerCoreCpuLoad() {\n        double[] loads = processor.getProcessorCpuLoadBetweenTicks(prevProcTicks);\n        prevProcTicks = processor.getProcessorCpuLoadTicks();\n        return loads; // Per-core loads\n    }\n\n    public double[] getSystemLoadAverage() {\n        double[] loadAverages = processor.getSystemLoadAverage(1);\n        if (loadAverages[0] < 0) {\n            // Load averages not available\n            java.util.Arrays.fill(loadAverages, 0.0);\n        }\n        return loadAverages;\n    }\n\n    private long getRawContextSwitches() {\n        // Use CentralProcessor's method to get context switches\n        long contextSwitches = processor.getContextSwitches();\n        return contextSwitches;\n    }\n\n    private long calculateContextSwitches() {\n        long currentContextSwitches = getRawContextSwitches();\n        long delta = currentContextSwitches - prevContextSwitches;\n        prevContextSwitches = currentContextSwitches;\n        return delta; // Context switches since last check\n    }\n\n    public double getCpuLoad() {\n        return cpuLoad;\n    }\n\n    public double[] getPerCoreLoads() {\n        return perCoreLoads;\n    }\n\n    public double[] getSystemLoadAverages() {\n        return systemLoadAverage;\n    }\n\n    public long getContextSwitches() {\n        return contextSwitches;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/Test.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.common;\n\nimport java.io.File;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * @author Adrian Muraru\n */\npublic class Test {\n    public static void main(String[] args) {\n\n        String sshFormat = \"((([a-zA-Z0-9][a-zA-Z0-9]*)@)?(([a-zA-Z0-9][a-zA-Z0-9\\\\-]*\\\\.?)+):)?((\" + (File.separatorChar == '\\\\' ? File.separatorChar : \"\") + File.separatorChar\n                + \"?[a-zA-Z_\\\\-0-9\\\\.]*)+)\";//\n        Pattern pattern = Pattern.compile(sshFormat);\n        Matcher match = pattern.matcher(\"dest.xml\");\n        System.out.println(match.matches());\n\n        String user = match.group(3);\n        if (user != null && user.trim().length() == 0)\n            user = null;\n        String host = match.group(4);\n        if (host != null && host.trim().length() == 0)\n            host = null;\n        String path = match.group(6);\n        if (path == null || path.trim().length() == 0)\n            path = \".\";\n        System.out.println(\" user \" + (user == null ? \"none\" : user) + \" host \" + host + \" path \" + path);\n\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/Test2MD5Sum.java",
    "content": "/* \n * \n * $Id$\n *\n * Created on December 19, 2006, 2:37 AM\n *\n */\n\npackage lia.util.net.common;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.TreeMap;\n\n/**\n * @author ramiro\n */\npublic class Test2MD5Sum {\n\n    /**\n     * Creates a new instance of Test2MD5Sum\n     */\n    public Test2MD5Sum() {\n    }\n\n    public static final void main(String[] args) throws Exception {\n\n        if (args.length != 2) {\n            System.err.println(\"Usage java -jar fdt.jar \" + Test2MD5Sum.class.getName() + \" md5sumFile1 md5sumFile2\");\n            System.exit(1);\n        }\n\n        TreeMap<String, String> firstMap = getMap(args[0]);\n        TreeMap<String, String> secondMap = getMap(args[1]);\n\n        System.out.println(\" FirstMaps size: \" + firstMap.size() + \" SecondMap size: \" + secondMap.size());\n\n        if (firstMap.size() != secondMap.size()) {\n            System.err.println(\" Different size() ... will exit\");\n            System.exit(1);\n        }\n\n        ArrayList<String> nokFList = new ArrayList<String>();\n        //check the first map\n        for (Map.Entry<String, String> entry : firstMap.entrySet()) {\n            final String fName = entry.getKey();\n            final String md5Sum = entry.getValue();\n\n            final String md5Check = secondMap.get(fName);\n\n            if (md5Check == null) {\n                System.err.println(\" The file \" + fName + \" form first map cannot be found in the second map\");\n                System.exit(1);\n            }\n\n            if (md5Check.equals(md5Sum)) {\n                System.out.println(\" File \" + fName + \" [ \" + md5Sum + \" ] is OK\");\n            } else {\n                System.err.println(\" File \" + fName + \" [ \" + md5Sum + \" ] is NOT OK\");\n                nokFList.add(fName);\n            }\n        }\n\n        if (nokFList.size() == 0) {\n            System.out.println(\" Total md5sums compared: \" + firstMap.size() + \" ... All OK!\");\n        } else {\n            System.out.println(\" Total md5sums compared: \" + firstMap.size() + \" ...  NOT OK = \" + nokFList.size());\n            int i = 1;\n            for (String fName : nokFList) {\n                System.out.println(\" NOKFile \" + (i++) + \" : \" + fName);\n            }\n        }\n\n    }\n\n    private static final TreeMap<String, String> getMap(final String fName) throws Exception {\n\n        BufferedReader br = new BufferedReader(new FileReader(fName));\n\n        String line;\n        TreeMap<String, String> map = new TreeMap<String, String>();\n\n        while ((line = br.readLine()) != null) {\n            int firstSpace = line.indexOf(\" \");\n            if (firstSpace < 0) {\n                System.out.println(\" Ignoring line \" + line + \" from file \" + fName);\n            } else {\n                map.put(line.substring(firstSpace + 1), line.substring(0, firstSpace));\n            }\n        }\n\n        br.close();\n\n        return map;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/Utils.java",
    "content": "package lia.util.net.common;\n\nimport apmon.ApMon;\nimport lia.gsi.FDTGSIServer;\nimport lia.util.net.copy.FDT;\nimport lia.util.net.copy.FDTServer;\nimport lia.util.net.copy.FDTSessionManager;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.transport.ControlChannel;\nimport lia.util.net.copy.transport.CtrlMsg;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.*;\nimport java.net.*;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.*;\nimport java.text.DecimalFormat;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.jar.Attributes;\nimport java.util.jar.JarFile;\nimport java.util.jar.Manifest;\nimport java.util.logging.Level;\nimport java.util.logging.LogManager;\nimport java.util.logging.Logger;\n\n/**\n * Various utilities functions used in the entire application\n *\n * @author ramiro\n */\npublic final class Utils {\n\n    public static final char ZERO = '0';\n    public static final int VALUE_2_STRING_NO_UNIT = 1;\n    public static final int VALUE_2_STRING_UNIT = 2;\n    public static final int VALUE_2_STRING_SHORT_UNIT = 3;\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(Utils.class.getName());\n    private static final ScheduledThreadPoolExecutor scheduledExecutor = getSchedExecService(\"FDT Monitoring ThPool\",\n            5, Thread.MIN_PRIORITY);\n    private static final int AV_PROCS;\n    private static final long KILO_BIT = 1000;\n    public static final long MEGA_BIT = KILO_BIT * 1000;\n    private static final long GIGA_BIT = MEGA_BIT * 1000;\n    private static final long TERA_BIT = GIGA_BIT * 1000;\n    private static final long PETA_BIT = TERA_BIT * 1000;\n    private static final long KILO_BYTE = 1024;\n    public static final long MEGA_BYTE = KILO_BYTE * 1024;\n    private static final long GIGA_BYTE = MEGA_BYTE * 1024;\n    private static final long TERA_BYTE = GIGA_BYTE * 1024;\n    private static final long PETA_BYTE = TERA_BYTE * 1024;\n    private static final long[] BYTE_MULTIPLIERS = new long[]{KILO_BYTE, MEGA_BYTE, GIGA_BYTE, TERA_BYTE, PETA_BYTE};\n    private static final String[] BYTE_SUFIXES = new String[]{\"KB\", \"MB\", \"GB\", \"TB\", \"PB\"};\n    private static final long[] BIT_MULTIPLIERS = new long[]{KILO_BIT, MEGA_BIT, GIGA_BIT, TERA_BIT, PETA_BIT};\n    private static final String[] BIT_SUFIXES = new String[]{\"Kb\", \"Mb\", \"Gb\", \"Tb\", \"Pb\"};\n    private static final int URL_CONNECTION_TIMEOUT = 20 * 1000;\n    private static final Object lock = new Object();\n    private static final long SECONDS_IN_MINUTE = TimeUnit.MINUTES.toSeconds(1);\n    private static final long SECONDS_IN_HOUR = TimeUnit.HOURS.toSeconds(1);\n    private static final long SECONDS_IN_DAY = TimeUnit.DAYS.toSeconds(1);\n    private static final String[] SELECTION_KEY_OPS_NAMES = {\"OP_ACCEPT\", \"OP_CONNECT\", \"OP_READ\", \"OP_WRITE\"};\n    private static final int[] SELECTION_KEY_OPS_VALUES = {SelectionKey.OP_ACCEPT, SelectionKey.OP_CONNECT,\n            SelectionKey.OP_READ, SelectionKey.OP_WRITE};\n    /**\n     * reference to the monitor reporting api, initialized in the constructor of {@link FDT}\n     */\n    private static ApMon apmon = null;\n    private static boolean apmonInitied = false;\n\n    //\n    // END this should not be here any more after FDT will use only Java6\n    // /\n\n    static {\n\n        int avProcs = Runtime.getRuntime().availableProcessors();\n\n        if (avProcs <= 0) {// smth is wrong with the JVM or the OS\n\n            avProcs = 1;\n        }\n\n        AV_PROCS = avProcs;\n\n    }\n\n    public static String getStackTrace(Throwable t) {\n        if (t == null) {\n            return \"Stack trace unavailable\";\n        }\n        StringWriter sw = new StringWriter();\n        t.printStackTrace(new PrintWriter(sw));\n        return sw.toString();\n    }\n\n    public static ScheduledThreadPoolExecutor getSchedExecService(final String name, final int corePoolSize,\n                                                                  final int threadPriority) {\n        return new ScheduledThreadPoolExecutor(corePoolSize, new ThreadFactory() {\n\n            AtomicLong l = new AtomicLong(0);\n\n            public Thread newThread(Runnable r) {\n                Thread t = new Thread(r, name + \" - WorkerTask \" + l.getAndIncrement());\n                t.setPriority(threadPriority);\n                t.setDaemon(true);\n                return t;\n            }\n        }, new RejectedExecutionHandler() {\n\n            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                try {\n                    if (executor.isShutdown() || executor.isTerminated() || executor.isTerminating()) {\n                        return;\n                    }\n                    // slow down a little bit\n                    final long SLEEP_TIME = Math.round((Math.random() * 1000D) + 1);\n                    try {\n                        Thread.sleep(SLEEP_TIME);\n                    } catch (Throwable ignore) {\n                        if (logger.isLoggable(Level.FINER)) {\n                            ignore.printStackTrace();\n                        }\n                    }\n                    System.err.println(\"\\n\\n [ RejectedExecutionHandler ] for \" + name + \" WorkerTask slept for \"\n                            + SLEEP_TIME);\n                    executor.execute(r);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n        });\n    }\n\n    public static ExecutorService getStandardExecService(final String name, final int corePoolSize,\n                                                         final int maxPoolSize, BlockingQueue<Runnable> taskQueue, final int threadPriority) {\n        ThreadPoolExecutor texecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 2 * 60, TimeUnit.SECONDS,\n                taskQueue, new ThreadFactory() {\n\n            final AtomicLong l = new AtomicLong(0);\n\n            public Thread newThread(Runnable r) {\n                Thread t = new Thread(r, name + \" - WorkerTask \" + l.getAndIncrement());\n                t.setPriority(threadPriority);\n                t.setDaemon(true);\n                return t;\n            }\n        });\n        texecutor.setRejectedExecutionHandler(new RejectedExecutionHandler() {\n\n            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                try {\n                    if (executor.isShutdown() || executor.isTerminated() || executor.isTerminating()) {\n                        return;\n                    }\n                    // slow down a little bit\n                    final long SLEEP_TIME = Math.round((Math.random() * 400D) + 1);\n                    try {\n                        Thread.sleep(SLEEP_TIME);\n                    } catch (Throwable ignore) {\n                        if (logger.isLoggable(Level.FINER)) {\n                            ignore.printStackTrace();\n                        }\n                    }\n                    System.err.println(\"\\n\\n [ RejectedExecutionHandler ] [ Full Throttle ] for \" + name\n                            + \" WorkerTask slept for \" + SLEEP_TIME);\n                    executor.getQueue().put(r);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n        });\n\n        texecutor.allowCoreThreadTimeOut(true);\n        texecutor.prestartAllCoreThreads();\n\n        return texecutor;\n    }\n\n    public static ExecutorService getStandardExecService(final String name, final int corePoolSize,\n                                                         final int maxPoolSize, final int threadPriority) {\n        return getStandardExecService(name, corePoolSize, maxPoolSize, new SynchronousQueue<Runnable>(), threadPriority);\n    }\n\n    public static String formatWithByteFactor(final double number, final long factor, final String append) {\n        String appendUM = \"\";\n        double fNo = number;\n\n        boolean bFound = false;\n        if (factor == 0) {\n            for (int i = BYTE_MULTIPLIERS.length - 1; i >= 0; i--) {\n                if (number > BYTE_MULTIPLIERS[i]) {\n                    fNo /= BYTE_MULTIPLIERS[i];\n                    appendUM = BYTE_SUFIXES[i];\n                    bFound = true;\n                    break;\n                }\n            }\n        } else {\n            for (int i = BYTE_MULTIPLIERS.length - 1; i >= 0; i--) {\n                if (factor == BYTE_MULTIPLIERS[i]) {\n                    fNo /= BYTE_MULTIPLIERS[i];\n                    appendUM = BYTE_SUFIXES[i];\n                    bFound = true;\n                    break;\n                }\n            }\n        }\n\n        if (!bFound) {\n            appendUM = \"B\";\n        }\n\n        appendUM += append;\n\n        return speedDecimalFormat(fNo) + ' ' + appendUM;\n    }\n\n    public static String formatWithBitFactor(final double number, final long factor, final String append) {\n        String appendUM = \"\";\n        double fNo = number;\n\n        boolean bFound = false;\n        if (factor == 0) {\n            for (int i = BIT_MULTIPLIERS.length - 1; i >= 0; i--) {\n                if (number > BIT_MULTIPLIERS[i]) {\n                    fNo /= BIT_MULTIPLIERS[i];\n                    appendUM = BIT_SUFIXES[i];\n                    bFound = true;\n                    break;\n                }\n            }\n\n        } else {\n            for (int i = BIT_MULTIPLIERS.length - 1; i >= 0; i--) {\n                if (factor == BIT_MULTIPLIERS[i]) {\n                    fNo /= BIT_MULTIPLIERS[i];\n                    appendUM = BIT_SUFIXES[i];\n                    bFound = true;\n                    break;\n                }\n            }\n        }\n\n        if (!bFound) {\n            appendUM = \"b\";\n        }\n        appendUM += append;\n\n        return speedDecimalFormat(fNo) + ' ' + appendUM;\n    }\n\n    private static String speedDecimalFormat(final double no) {\n        final DecimalFormat SPEED_DECIMAL_FORMAT = ((DecimalFormat) DecimalFormat.getNumberInstance());\n        SPEED_DECIMAL_FORMAT.applyPattern(\"##0.000\");\n        return SPEED_DECIMAL_FORMAT.format(no);\n    }\n\n    public static String percentDecimalFormat(final double no) {\n        final DecimalFormat PERCENT_DECIMAL_FORMAT = ((DecimalFormat) DecimalFormat.getNumberInstance());\n        PERCENT_DECIMAL_FORMAT.applyPattern(\"00.00\");\n        return PERCENT_DECIMAL_FORMAT.format(no);\n    }\n\n    public static String getETA(final long seconds) {\n        long delta = seconds;\n        StringBuilder sb = new StringBuilder();\n        final long days = seconds / SECONDS_IN_DAY;\n        if (days > 0) {\n            if (days < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(days).append(\"d \");\n            delta -= days * SECONDS_IN_DAY;\n        }\n\n        final long hours = delta / SECONDS_IN_HOUR;\n        if (hours > 0) {\n            delta -= hours * SECONDS_IN_HOUR;\n            if (hours < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(hours).append(\"h \");\n        }\n\n        if (days > 0) {\n            return sb.toString();\n        }\n\n        final long minutes = delta / SECONDS_IN_MINUTE;\n        if (minutes > 0) {\n            if (minutes < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(minutes).append(\"m \");\n            delta -= minutes * SECONDS_IN_MINUTE;\n        }\n\n        if (hours > 0) {\n            return sb.toString();\n        }\n\n        if (delta < 10) {\n            sb.append(ZERO);\n        }\n        sb.append(delta).append('s');\n\n        return sb.toString();\n    }\n\n    /**\n     * Works with both Java5 and Java6 ....... Uncooment the code and remove ............\n     *\n     * @param value\n     * @param unit\n     * @return the ETA as String representation\n     * @since Java 1.6\n     */\n    public static String getETA(final long value, TimeUnit unit) {\n        long delta = value;\n\n        StringBuilder sb = new StringBuilder();\n\n        // TimeUnit.DAYS N/A in 1.5\n        final long days = TimeUnit.DAYS.convert(delta, unit);\n        if (days > 0) {\n            if (days < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(days).append(\"d \");\n            delta -= unit.convert(days, TimeUnit.DAYS);\n        }\n\n        long hours = TimeUnit.HOURS.convert(delta, unit);\n        if (hours > 0) {\n            delta -= unit.convert(hours, TimeUnit.HOURS);\n            if (hours < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(hours).append(\"h \");\n        }\n\n        if (days > 0) {\n            return sb.toString();\n        }\n\n        final long minutes = TimeUnit.MINUTES.convert(delta, unit);\n        if (minutes > 0) {\n            if (minutes < 10) {\n                sb.append(ZERO);\n            }\n            sb.append(minutes).append(\"m \");\n            delta -= unit.convert(minutes, TimeUnit.MINUTES);\n        }\n\n        if (hours > 0) {\n            return sb.toString();\n        }\n\n        if (delta < 10) {\n            sb.append(ZERO);\n        }\n        sb.append(delta).append('s');\n\n        return sb.toString();\n    }\n\n    public static ScheduledThreadPoolExecutor getMonitoringExecService() {\n        return scheduledExecutor;\n    }\n\n    public static DirectByteBufferPool getDirectBufferPool() {\n        return DirectByteBufferPool.getInstance();\n    }\n\n    public static int availableProcessors() {\n        return AV_PROCS;\n    }\n\n    public static HeaderBufferPool getHeaderBufferPool() {\n        return HeaderBufferPool.getInstance();\n    }\n\n    public static void initApMonInstance(ApMon apmon) throws Exception {\n        synchronized (Utils.class) {\n            if (apmonInitied) {\n                return;\n            }\n\n            Utils.apmon = apmon;\n            apmonInitied = true;\n\n            Utils.class.notifyAll();\n        }\n    }\n\n    public static ApMon getApMon() {\n        synchronized (Utils.class) {\n\n            // just check that initApMonInstance will be ever called ....\n            Config config = Config.getInstance();\n            if (config.getApMonHosts() == null && !config.getMonitor().equals(config.OPENTSDB)) {\n                return null;\n            }\n\n            while (!apmonInitied) {\n                try {\n                    Utils.class.wait();\n                } catch (Exception ex) {\n                    ex.printStackTrace();\n                }\n            }\n\n            return apmon;\n        }\n    }\n\n    public static boolean isCustomLog() {\n        final String customLogProperty = System.getProperty(\"CustomLog\");\n        boolean bCustomLog = false;\n        if (customLogProperty != null) {\n            final String trimLower = customLogProperty.trim().toLowerCase();\n            if (!trimLower.isEmpty()) {\n                bCustomLog = trimLower.startsWith(\"t\") || trimLower.startsWith(\"1\") || trimLower.startsWith(\"on\");\n            }\n        }\n\n        return bCustomLog;\n    }\n\n    public static String buffToString(final ByteBuffer bb) {\n\n        if (bb == null) {\n            return \"null\";\n        }\n\n        StringBuilder sb = new StringBuilder(512);\n        sb.append(bb).append(\" id=\").append(System.identityHashCode(bb)).append(' ');\n\n        return sb.toString();\n    }\n\n    // TODO - should not parse here -c -d -bullshit\n    public static Map<String, Object> parseArguments(final String args[], final String[] singleArgs) {\n\n        List<String> sArgs = Arrays.asList(singleArgs);\n\n        final Map<String, Object> rHM = new HashMap<String, Object>();\n        if ((args == null) || (args.length == 0)) {\n            return rHM;\n        }\n\n        List<String> lParams = new ArrayList<String>();\n\n        ArrayList<String> sshUsers = new ArrayList<String>();\n        ArrayList<String> sshHosts = new ArrayList<String>();\n        ArrayList<String> sshFiles = new ArrayList<String>();\n\n        int i = 0;\n        for (i = 0; i < args.length; i++) {\n            if (args[i].startsWith(\"-\")) {\n                if ((i == (args.length - 1)) || args[i + 1].startsWith(\"-\") || sArgs.contains(args[i])) {\n                    rHM.put(args[i], \"\");\n                } else {\n                    if ((sshUsers.size() > 0) && (args[i].equals(\"-c\") || args[i].equals(\"-d\"))) {\n                        throw new IllegalArgumentException(\n                                \"Illegal syntax! You can use either either Client/Server (-c/-d) syntax, either SCP syntax\");\n                    }\n\n                    rHM.put(args[i], args[i + 1]);\n                    i++;\n                }\n            } else if (args[i].contains(\":\")) {\n                int idx = args[i].indexOf(':');\n\n                // /////////////\n                // handle windows stupid FS naming\n                // ////////////\n                if (File.separatorChar == '\\\\') {// \"Windowns\" baby!\n\n                    if ((idx + 1) == args[i].length()) {\n                        // ////////////\n                        // tricky scp-like command from windows\n                        //\n                        // java -jar fdt.jar C:\\x n:\n                        //\n                        // where n may be a remote machine, and C:\\x a file\n                        //\n                        // check that we have a single letter before ':'\n                        // ///////////////\n\n                        if ((idx - 1) == 0) {\n\n                            // test if it is a File\n                            if (new File(args[i].charAt(0) + \":\").exists()) {\n                                // stupid driver letter; got you\n                                if (sshUsers.size() > 0) {\n                                    // I am the destination directory\n                                    rHM.put(\"destinationDir\", args[i]);\n                                    rHM.put(\"-d\", rHM.get(\"destinationDir\"));\n                                    break;\n                                }\n\n                                lParams.add(args[i]);\n                                continue;\n                            }\n                        }\n                    }\n\n                    if (((idx + 1) < args[i].length()) && (args[i].charAt(idx + 1) == File.separatorChar)) {\n                        if (sshUsers.size() > 0) {\n                            // I am the destination directory\n                            rHM.put(\"destinationDir\", args[i]);\n                            rHM.put(\"-d\", rHM.get(\"destinationDir\"));\n                            break;\n                        }\n\n                        lParams.add(args[i]);\n                        continue;\n                    }\n                }\n\n                // /////////////\n                // END handle windows stupid FS naming\n                // ////////////\n\n                // SSH mode\n\n                // System.out.print(\" SCP Match: \" + args[i]);\n                if ((sshUsers.size() == 0) && ((rHM.get(\"-d\") != null) || (rHM.get(\"-c\") != null))) {\n                    throw new IllegalArgumentException(\n                            \"Illegal syntax! You can use either Client/Server (-c/-d) syntax, either SCP syntax\");\n                }\n\n                String userHost = null;\n                if (idx > 0) {\n                    userHost = args[i].substring(0, idx);\n                }\n\n                String user = null;\n                String host = null;\n                String path = null;\n                if (userHost != null) {\n                    int idx1 = userHost.indexOf(\"@\");\n                    if (idx1 >= 0) { // at least user\n\n                        if (idx1 == 0) {\n                            throw new IllegalArgumentException(\"Invalid scp syntax for \" + args[i]);\n                        }\n\n                        user = userHost.substring(0, idx1);\n                        if ((idx1 + 1) < userHost.length()) {\n                            host = userHost.substring(idx1 + 1);\n                        } else {\n                            throw new IllegalArgumentException(\"Invalid scp syntax for \" + args[i]);\n                        }\n                    } else {\n                        host = userHost;\n                    }\n                }\n\n                if ((idx + 1) == args[i].length()) {\n                    path = \".\";\n                } else {\n                    path = args[i].substring(idx + 1);\n                }\n\n                // if (alSSH == null)\n                // alSSH = new ArrayList<String[]>();\n\n                sshUsers.add(user);\n                sshHosts.add(host);\n                sshFiles.add(path);\n            } else {\n                if (sshUsers.size() > 0) {\n                    // I am the destination directory\n                    rHM.put(\"destinationDir\", args[i]);\n                    rHM.put(\"-d\", rHM.get(\"destinationDir\"));\n                    break;\n                }\n\n                lParams.add(args[i]);\n            }\n        }// for\n\n        int sshHostsNo = sshUsers.size();\n        if (sshHostsNo > 0) {\n            rHM.put(\"SCPSyntaxUsed\", Boolean.TRUE);\n\n            if (rHM.get(\"destinationDir\") == null) {\n                // the last one should be the destination\n\n                rHM.put(\"destinationUser\", sshUsers.get(sshHostsNo - 1));\n                rHM.put(\"destinationHost\", sshHosts.get(sshHostsNo - 1));\n                rHM.put(\"destinationDir\", sshFiles.get(sshHostsNo - 1));\n                rHM.put(\"-d\", rHM.get(\"destinationDir\"));\n                rHM.put(\"-c\", rHM.get(\"destinationHost\"));\n\n                // remove the destination from the SSH/SCP args\n                sshUsers.remove(sshHostsNo - 1);\n                sshHosts.remove(sshHostsNo - 1);\n                sshFiles.remove(sshHostsNo - 1);\n\n            }\n\n            sshHostsNo = sshUsers.size();\n\n            if (sshHostsNo > 0) {\n                // the source hosts\n                final String[] sUsers = sshUsers.toArray(new String[sshHostsNo]);\n                final String[] sHosts = sshHosts.toArray(new String[sshHostsNo]);\n                final String[] sFiles = sshFiles.toArray(new String[sshHostsNo]);\n\n                rHM.put(\"sourceUsers\", sUsers);\n                rHM.put(\"sourceHosts\", sHosts);\n                rHM.put(\"sourceFiles\", sFiles);\n\n                rHM.put(\"Files\", rHM.get(\"sourceFiles\"));\n            }\n        }\n\n        rHM.put(\"LastParams\", lParams);\n\n        return rHM;\n    }\n\n    static String getStringValue(final Map<String, Object> configMap, String key, String DEFAULT_VALUE) {\n        Object obj = configMap.get(key);\n        if (obj == null) {\n            return DEFAULT_VALUE;\n        }\n\n        return obj.toString();\n    }\n\n    public static long getLongValue(final Map<String, Object> configMap, final String key,\n                                    final long DEFAULT_VALUE) {\n        long rVal;\n        Object obj = configMap.get(key);\n        if (obj == null) {\n            rVal = DEFAULT_VALUE;\n        } else {\n            String cVal = obj.toString();\n            if (cVal.length() == 0) {\n                rVal = DEFAULT_VALUE;\n            } else {\n                try {\n\n                    long factor = 1;\n                    if (cVal.endsWith(\"K\") || cVal.endsWith(\"k\")) {\n                        factor = Utils.KILO_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"M\") || cVal.endsWith(\"m\")) {\n                        factor = Utils.MEGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"G\") || cVal.endsWith(\"g\")) {\n                        factor = Utils.GIGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    }\n\n                    rVal = Long.parseLong(cVal) * factor;\n                } catch (Throwable t) {\n                    rVal = DEFAULT_VALUE;\n                }\n            }\n        }\n        return rVal;\n    }\n\n    public static double getDoubleValue(final Map<String, Object> configMap, final String key,\n                                        final double DEFAULT_VALUE) {\n\n        double rVal;\n        Object obj = configMap.get(key);\n        if (obj == null) {\n            rVal = DEFAULT_VALUE;\n        } else {\n            String cVal = obj.toString();\n            if (cVal.length() == 0) {\n                rVal = DEFAULT_VALUE;\n            } else {\n                try {\n\n                    double factor = 1;\n                    if (cVal.endsWith(\"K\") || cVal.endsWith(\"k\")) {\n                        factor = Utils.KILO_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"M\") || cVal.endsWith(\"m\")) {\n                        factor = Utils.MEGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"G\") || cVal.endsWith(\"g\")) {\n                        factor = Utils.GIGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    }\n\n                    rVal = Double.parseDouble(cVal) * factor;\n                } catch (Throwable t) {\n                    rVal = DEFAULT_VALUE;\n                }\n            }\n        }\n        return rVal;\n    }\n\n    public static int getIntValue(final Map<String, Object> configMap, final String key, final int DEFAULT_VALUE) {\n\n        int rVal;\n        Object obj = configMap.get(key);\n        if (obj == null) {\n            rVal = DEFAULT_VALUE;\n        } else {\n            String cVal = obj.toString();\n            if (cVal.length() == 0) {\n                rVal = DEFAULT_VALUE;\n            } else {\n                try {\n\n                    long factor = 1;\n                    if (cVal.endsWith(\"K\") || cVal.endsWith(\"k\")) {\n                        factor = Utils.KILO_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"M\") || cVal.endsWith(\"m\")) {\n                        factor = Utils.MEGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    } else if (cVal.endsWith(\"G\") || cVal.endsWith(\"g\")) {\n                        factor = Utils.GIGA_BYTE;\n                        cVal = cVal.substring(0, cVal.length() - 1);\n                    }\n\n                    rVal = Integer.parseInt(cVal) * (int) factor;\n                } catch (Throwable t) {\n                    rVal = DEFAULT_VALUE;\n                }\n            }\n        }\n        return rVal;\n    }\n\n    private static File createOrGetRWFile(final String parentDirName, final String fileName) {\n\n        final File parentDir = new File(parentDirName);\n        final File file = new File(parentDirName + File.separator + fileName);\n\n        if (!parentDir.exists()) {\n            if (parentDir.mkdirs()) {\n                return null;\n            }\n        }\n\n        try {\n            if (!file.exists()) {\n                if (file.createNewFile()) {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \"Created update conf file:\" + file);\n                    }\n                } else {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \"Cannot create update conf file:\" + file);\n                    }\n\n                    return null;\n                }\n            } else {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"File: \" + file + \"exists. \");\n                }\n            }\n\n            if (file.canRead()) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"File: \" + file + \" can be read.\");\n                }\n\n                if (file.canWrite()) {\n                    if (logger.isLoggable(Level.FINER)) {\n                        logger.log(Level.FINER, \"File: \" + file + \" can be written.\");\n                    }\n                    return file;\n                }\n\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"File: \" + file + \" can not be written.\");\n                }\n            } else {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"File: \" + file + \" can not be read.\");\n                }\n            }\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Cannot create \" + file, t);\n        }\n\n        return null;\n    }\n\n    public static void updatePropertyAndStore(String dirName, String fileName, String property, String value) {\n\n        synchronized (lock) {\n            final File file = createOrGetRWFile(dirName, fileName);\n            if (file != null) {\n                FileInputStream fis = null;\n                FileOutputStream fos = null;\n                try {\n                    final Properties props = new Properties();\n                    fis = new FileInputStream(file);\n                    props.load(fis);\n\n                    props.put(property, value);\n\n                    fos = new FileOutputStream(file);\n                    props.store(fos, null);\n                    fos.flush();\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \"Cannot update \" + file, t);\n                    }\n                } finally {\n                    closeIgnoringExceptions(fis);\n                    closeIgnoringExceptions(fos);\n                }\n            }\n        }\n\n    }\n\n    private static Properties getFDTUpdateProperties() {\n        final String parentFDTConfDirName = System.getProperty(\"user.home\") + File.separator + \".fdt\";\n        final String fdtUpdateConfFileName = \"update.properties\";\n        Properties updateProperties = new Properties();\n        final File confFile = createOrGetRWFile(parentFDTConfDirName, fdtUpdateConfFileName);\n\n        if (confFile != null) {\n            FileInputStream fis = null;\n\n            try {\n                fis = new FileInputStream(confFile);\n                updateProperties.load(fis);\n            } catch (Throwable t) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"Unable to read properties file: \" + confFile, t);\n                }\n            } finally {\n                closeIgnoringExceptions(fis);\n            }\n        }\n        return updateProperties;\n    }\n\n    private static boolean updateTotalCounter(final long total, final String property) {\n\n        final String parentFDTConfDirName = System.getProperty(\"user.home\") + File.separator + \".fdt\";\n        final String fdtUpdateConfFileName = \"update.properties\";\n        final File confFile = createOrGetRWFile(parentFDTConfDirName, fdtUpdateConfFileName);\n\n        if (confFile != null) {\n            Properties updateProperties = new Properties();\n            FileInputStream fis = null;\n            FileOutputStream fos = null;\n\n            try {\n                fis = new FileInputStream(confFile);\n                updateProperties.load(fis);\n\n                closeIgnoringExceptions(fis);\n\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" [ Utils ] [ updateTotalContor ] loaded properties: {0}\",\n                            updateProperties);\n                }\n\n                final String contorStringValue = (String) updateProperties.get(property);\n                final String rstStringValue = (String) updateProperties.get(property + \"_rst\");\n\n                long lastContor = 0;\n                long rstContor = 0;\n\n                if (contorStringValue != null) {\n                    try {\n                        lastContor = Long.parseLong(contorStringValue);\n                        rstContor = Long.parseLong(rstStringValue);\n                    } catch (Throwable t) {\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \"Got exception parsing \" + property + \" param\", t);\n                        }\n                        lastContor = 0;\n                        rstContor = 0;\n                    }\n                }\n\n                lastContor += total;\n                if (lastContor < 0) {\n                    rstContor++;\n                }\n\n                updateProperties.put(property, String.valueOf(lastContor));\n                updateProperties.put(property + \"_rst\", String.valueOf(rstContor));\n\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" [ Utils ] [ updateTotalContor ] store new properties: {0}\",\n                            updateProperties);\n                }\n\n                checkAndSetInstanceID(updateProperties);\n\n                fos = new FileOutputStream(confFile);\n                updateProperties.store(fos, null);\n                fos.flush();\n\n            } catch (Throwable t) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"Unable to update properties file for property: \" + property + \" contor: \"\n                            + total + \" file: \" + confFile, t);\n                }\n                return false;\n            } finally {\n                closeIgnoringExceptions(fis);\n                closeIgnoringExceptions(fos);\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * @param props\n     * @since FDT 0.9.0 - basic instanceID per FDT instance\n     */\n    private static void checkAndSetInstanceID(final Properties props) {\n\n        if (props == null) {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \" [ Utils ] [ checkAndSetInstanceID ] Null properties ... nothing to check/set\");\n            }\n            return;\n        }\n\n        try {\n            String instID = props.getProperty(\"instanceID\");\n\n            if ((instID == null) || instID.trim().isEmpty()) {\n                instID = UUID.randomUUID().toString();\n                props.put(\"instanceID\", instID);\n\n                final String parentFDTConfDirName = System.getProperty(\"user.home\") + File.separator + \".fdt\";\n                final String fdtUpdateConfFileName = \"update.properties\";\n                final File confFile = createOrGetRWFile(parentFDTConfDirName, fdtUpdateConfFileName);\n                FileOutputStream fos = null;\n\n                if (confFile != null) {\n                    try {\n                        fos = new FileOutputStream(confFile);\n                        props.store(fos, null);\n                        fos.flush();\n                    } catch (Throwable ignore) {\n                        if (logger.isLoggable(Level.FINEST)) {\n                            ignore.printStackTrace();\n                        }\n                    } finally {\n                        closeIgnoringExceptions(fos);\n                    }\n                }\n            }\n        } catch (Throwable ignore) {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \" [ Utils ] [ checkAndSetInstanceID ] Unable to get/set instanceID\", ignore);\n            }\n        }\n\n    }\n\n    public static boolean updateTotalReadCounter(final long totalRead) throws Exception {\n        return updateTotalCounter(totalRead, \"totalRead\");\n    }\n\n    public static boolean updateTotalWriteCounter(final long totalWrite) throws Exception {\n        return updateTotalCounter(totalWrite, \"totalWrite\");\n    }\n\n    /**\n     * @param fileBlockQueue\n     * @return - number of \"recovered\" FileBlock-s\n     */\n    public static int drainFileBlockQueue(Queue<FileBlock> fileBlockQueue) {\n        final boolean isInterrupted = Thread.interrupted();\n        int status = 0;\n        final DirectByteBufferPool bPool = DirectByteBufferPool.getInstance();\n        try {\n            if (fileBlockQueue == null) {\n                return status;\n            }\n\n            for (; ; ) {\n                try {\n                    final FileBlock fb = fileBlockQueue.poll();\n                    if (fb == null) {\n                        return status;\n                    }\n                    bPool.put(fb.buff);\n                    status++;\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" Got exception draining fileBlockQueue\", t);\n                }\n            }\n        } finally {\n            if (isInterrupted) {\n                try {\n                    Thread.currentThread().interrupt();\n                } catch (Throwable ignore) {\n                    // not interested\n                }\n            }\n        }\n    }\n\n    public static boolean checkForUpdate(final String currentVersion, final String updateURL, boolean noLock)\n            throws Exception {\n        try {\n            final String parentFDTConfDirName = System.getProperty(\"user.home\") + File.separator + \".fdt\";\n            final String fdtUpdateConfFileName = \"update.properties\";\n            final File confFile = createOrGetRWFile(parentFDTConfDirName, fdtUpdateConfFileName);\n\n            if (confFile != null) {\n                long lastCheck = 0;\n\n                Properties updateProperties = new Properties();\n                FileInputStream fis = null;\n                FileOutputStream fos = null;\n\n                try {\n                    fis = new FileInputStream(confFile);\n                    updateProperties.load(fis);\n\n                    final String lastCheckProp = (String) updateProperties.get(\"LastCheck\");\n\n                    lastCheck = 0;\n\n                    if (lastCheckProp != null) {\n                        try {\n                            lastCheck = Long.parseLong(lastCheckProp);\n                        } catch (Throwable t) {\n                            if (logger.isLoggable(Level.FINE)) {\n                                logger.log(Level.FINE, \"Got exception parsing LastCheck param\", t);\n                            }\n                            lastCheck = 0;\n                        }\n                    }\n\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Cannot load update properties file: \" + confFile, t);\n                } finally {\n                    closeIgnoringExceptions(fis);\n                }\n\n                final long now = System.currentTimeMillis();\n                boolean bHaveUpdates = false;\n                checkAndSetInstanceID(updateProperties);\n\n                if ((lastCheck + FDT.UPDATE_PERIOD) < now) {\n                    try {\n                        System.out\n                                .println(\"\\n\\nChecking for remote updates ... This may be disabled using -noupdates flag.\");\n                        bHaveUpdates = updateFDT(currentVersion, updateURL, false, noLock);\n                        if (bHaveUpdates) {\n                            logger.info(\"FDT may be updated using: java -jar fdt.jar -update\");\n                        } else {\n                            if (logger.isLoggable(Level.FINE)) {\n                                logger.log(Level.FINE, \"No updates available\");\n                            }\n                        }\n                    } catch (Throwable t) {\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.WARNING, \"Got exception\", t);\n                        }\n\n                    }\n\n                    updateProperties.put(\"LastCheck\", String.valueOf(now));\n\n                    try {\n                        fos = new FileOutputStream(confFile);\n                        updateProperties.store(fos, null);\n                    } catch (Throwable t1) {\n                        logger.log(Level.WARNING, \"Cannot store update properties file\", t1);\n                    } finally {\n                        closeIgnoringExceptions(fos);\n                    }\n\n                    return bHaveUpdates;\n                }\n            } else {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \" [ checkForUpdate ] Cannot read or write the update conf file: \"\n                            + parentFDTConfDirName + File.separator + fdtUpdateConfFileName);\n                }\n                return false;\n            }\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception checking for updates\", t);\n        }\n\n        return false;\n    }\n\n    /**\n     * @return true if update was available and FDT was successfully updated, and false if no update was available\n     * @throws Exception if update was unsuccessfully or there was a problem connecting to the update server\n     */\n    public static boolean updateFDT(final String currentVersion, final String updateURL, boolean shouldUpdate,\n                                    boolean noLock) throws Exception {\n\n        logger.info(\"Checking remote fdt.jar at URL: \" + updateURL);\n        final Properties p = getFDTUpdateProperties();\n\n        if (p.getProperty(\"totalRead\") == null) {\n            p.put(\"totalRead\", \"0\");\n        }\n\n        if (p.getProperty(\"totalWrite\") == null) {\n            p.put(\"totalWrite\", \"0\");\n        }\n\n        checkAndSetInstanceID(p);\n\n        if (p.getProperty(\"totalRead_rst\") != null) {\n            p.remove(\"totalRead_rst\");\n        }\n\n        if (p.getProperty(\"totalWrite_rst\") != null) {\n            p.remove(\"totalWrite_rst\");\n        }\n\n\n        final String finalPath = new URI(FDT.class.getProtectionDomain().getCodeSource().getLocation().toString()).getPath();\n\n        if ((finalPath == null) || (finalPath.length() == 0)) {\n            throw new IOException(\"Cannot determine the path to current fdt jar\");\n        }\n\n        final File currentJar = new File(finalPath);\n\n        if (!currentJar.exists()) {\n            // Smth wrong with the OS or the JVM?\n            throw new IOException(\"Current fdt.jar path seems to be [ \" + finalPath\n                    + \" ] but the JVM cannot access it!\");\n        }\n\n        if (currentJar.isFile() && currentJar.canWrite()) {\n            logger.info(\"\\nCurrent fdt.jar path is: \" + finalPath);\n        } else {\n            throw new IOException(\"Current fdt.jar path seems to be [ \" + finalPath\n                    + \" ] but it does not have write access!\");\n        }\n\n        // Check if it is possible to use a temporary file\n        File tmpUpdateFile = null;\n        FileOutputStream fos = null;\n        JarFile jf;\n        InputStream connInputStream = null;\n        try {\n            // first try to create the destination update file\n            tmpUpdateFile = File.createTempFile(\"fdt_update_tmp\", \".jar\");\n            tmpUpdateFile.deleteOnExit();\n            fos = new FileOutputStream(tmpUpdateFile);\n            if (updateURL.equals(FDT.UPDATE_URL)) {\n                connInputStream = connectTo(updateURL);\n                logger.info(\"OK\");\n                JSONObject jsonObject = getJsonInfo(connInputStream);\n                String tagName = getTagName(jsonObject);\n                String currentVersionString = currentVersion.substring(0, tagName.length());\n                logger.info(\"Current version: \" + currentVersionString + \" Latest version: \" + tagName);\n                if (currentVersionString.equals(tagName)) {\n                    logger.info(\"No need to update\");\n                    return false;\n                }\n                logAdditionalInfo(jsonObject);\n                String downloadUrl = getDownloadURL(jsonObject);\n                downloadFDT(fos, downloadUrl);\n                // try to check the version\n            } else {\n                downloadFDT(fos, updateURL);\n            }\n            jf = new JarFile(tmpUpdateFile);\n            final Manifest mf = jf.getManifest();\n            final Attributes attr = mf.getMainAttributes();\n            final String remoteVersion = attr.getValue(\"Implementation-Version\");\n\n            if (!Boolean.getBoolean(\"skip.version.check\")) {\n                if ((remoteVersion == null) || (remoteVersion.trim().length() == 0)) {\n                    throw new Exception(\"Cannot read the version from the downloaded jar...Cannot compare versions! \" +\n                            \"You can skip version checking by using system property: skip.version.check\");\n                }\n\n                if (currentVersion.equals(remoteVersion.trim())) {\n                    // no need for update\n                    return false;\n                }\n                logger.info(\"Remote FDT version: \" + remoteVersion + \" Local FDT version: \" + currentVersion\n                        + \". Update available.\");\n            } else {\n                logger.info(\"Skipped version checking.\");\n            }\n\n            if (shouldUpdate) {\n                try {\n\n                    // basic checks for parent directory\n                    final String parent = currentJar.getParent();\n                    if (parent == null) {\n                        throw new IOException(\"Unable to determine parent dir for: \" + currentJar);\n                    }\n                    final File parentDir = new File(parent);\n                    if (!parentDir.canWrite()) {\n                        //\n                        // windows XP (at least on the system I tested) reports totaly stupid things here; make it an\n                        // warning...\n                        //\n                        logger.log(Level.WARNING,\n                                \"[ WARNING CHECK ] The OS reported that is unable to write in parent dir: \" + parentDir\n                                        + \" continue anyway; the call might be broken.\");\n                    }\n\n                    final File bkpJar = new File(parentDir.getPath() + File.separator + \"fdt_\"\n                            + Config.FDT_FULL_VERSION + \".jar\");\n                    boolean bDel = bkpJar.exists();\n                    if (bDel) {\n                        bDel = bkpJar.delete();\n                        if (!bDel) {\n                            logger.info(\"[ WARNING ] Unable to delete backup jar with the same version: \"\n                                    + bkpJar + \" ... will continue\");\n                        } else {\n                            logger.info(\"[ INFO ] Backup jar (same version as the update) \" + bkpJar\n                                    + \" delete it.\");\n                        }\n                    }\n\n                    boolean renameSucced = currentJar.renameTo(bkpJar);\n                    if (!renameSucced) {\n                        logger.log(Level.WARNING, \"Unable to create backup: \" + bkpJar\n                                + \" for current FDT before update.\");\n                    } else {\n                        logger.info(\"Backing up old FDT succeeded: \" + bkpJar);\n                    }\n\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Unable to create a backup for current FDT before update. Exception: \", t);\n                }\n                copyFile2File(tmpUpdateFile, currentJar, noLock);\n            }\n\n            return true;\n        } finally {\n            closeIgnoringExceptions(connInputStream);\n            closeIgnoringExceptions(fos);\n            if (tmpUpdateFile != null) {\n                try {\n                    tmpUpdateFile.delete();\n                } catch (Throwable ignore) {\n                    // not interested\n                }\n            }\n        }\n    }\n\n    private static void downloadFDT(FileOutputStream fos, String downloadURL) throws IOException {\n        InputStream downInputStream;\n        if (!downloadURL.endsWith(\"fdt.jar\")) {\n            if (!downloadURL.endsWith(\"/\")) {\n                downloadURL = downloadURL + \"/fdt.jar\";\n            } else {\n                downloadURL = downloadURL + \"fdt.jar\";\n            }\n        }\n        logger.info(\"Trying to download update from \" + downloadURL);\n        downInputStream = connectTo(downloadURL);\n        logger.info(\"OK\");\n        byte[] buff = new byte[8192];\n\n        int count;\n        while ((count = downInputStream.read(buff)) > 0) {\n            fos.write(buff, 0, count);\n        }\n        fos.flush();\n    }\n\n    private static void logAdditionalInfo(JSONObject jsonObject) throws JSONException {\n        logReleaseName(jsonObject);\n        logPublishDate(jsonObject);\n        logReleaseNotes(jsonObject);\n    }\n\n    private static void logReleaseName(JSONObject jsonObject) throws JSONException {\n        String name = (String) jsonObject.get(\"name\");\n        logger.info(\"Name: \" + name);\n    }\n\n    private static void logReleaseNotes(JSONObject jsonObject) throws JSONException {\n        String body = (String) jsonObject.get(\"body\");\n        logger.info(\"Release notes: \" + body);\n    }\n\n    private static String getDownloadURL(JSONObject jsonObject) throws JSONException {\n        JSONArray assets = (JSONArray) jsonObject.get(\"assets\");\n        JSONObject asset = new JSONObject(assets.get(0).toString());\n        String downloadUrl = (String) asset.get(\"browser_download_url\");\n        logger.info(\"FDT download url: \" + downloadUrl);\n        return downloadUrl;\n    }\n\n    private static String logPublishDate(JSONObject jsonObject) throws JSONException {\n        String publishedAt = (String) jsonObject.get(\"published_at\");\n        logger.info(\"Publish date: \" + publishedAt);\n        return publishedAt;\n    }\n\n    private static JSONObject getJsonInfo(InputStream connInputStream) throws IOException, JSONException {\n        BufferedReader streamReader = new BufferedReader(new InputStreamReader(connInputStream, \"UTF-8\"));\n        StringBuilder responseStrBuilder = new StringBuilder(10);\n        String inputStr;\n        while ((inputStr = streamReader.readLine()) != null)\n            responseStrBuilder.append(inputStr);\n\n        String response = responseStrBuilder.toString();\n        response = getJsonString(response);\n        return new JSONObject(response);\n    }\n\n    private static String getTagName(JSONObject jsonObject) throws JSONException {\n        String tag_name = (String) jsonObject.get(\"tag_name\");\n        logger.info(\"Latest available version: \" + tag_name);\n        return tag_name;\n    }\n\n    private static String getJsonString(String response) {\n        if (response.startsWith(\"[\"))\n            response = response.substring(1);\n        if (response.endsWith(\"]\"))\n            response = response.substring(0, response.length() - 1);\n        return response;\n    }\n\n    private static InputStream connectTo(String updateURL) throws IOException {\n\n        final URLConnection urlConnection = new URL(updateURL).openConnection();\n        urlConnection.setDefaultUseCaches(false);\n        urlConnection.setUseCaches(false);\n        urlConnection.setConnectTimeout(URL_CONNECTION_TIMEOUT);\n        urlConnection.setReadTimeout(URL_CONNECTION_TIMEOUT);\n\n        logger.info(\"Connecting ... \");\n        urlConnection.connect();\n        return urlConnection.getInputStream();\n    }\n\n    public static String getUsage() {\n        final String newline = System.getProperty(\"line.separator\");\n\n        try {\n            BufferedReader br = new BufferedReader(new InputStreamReader(Utils.class.getResourceAsStream(\"usage\")));\n            StringBuilder sb = new StringBuilder();\n            for (; ; ) {\n                final String line = br.readLine();\n                if (line == null) {\n                    break;\n                }\n                sb.append(line).append(newline);\n            }\n\n            return sb.toString();\n        } catch (Throwable t) {\n            return \"Unable to load help msg.\";\n        }\n    }\n\n    public static String md5ToString(byte[] md5sum) {\n        StringBuilder sb = new StringBuilder();\n\n        for (byte element : md5sum) {\n            sb.append(Integer.toString((element & 0xff) + 0x100, 16).substring(1));\n        }\n\n        return sb.toString();\n    }\n\n    /**\n     * Optimized file transfer method. In most moder OS-es \"zero-copy\" should be used by the underlying OS.\n     *\n     * @param s source file\n     * @param d destination file\n     * @throws IOException\n     */\n    private static void copyFile2File(File s, File d, boolean noLock) throws IOException {\n        FileChannel srcChannel = null;\n        FileChannel dstChannel = null;\n\n        RandomAccessFile raf = null;\n        FileOutputStream fos = null;\n\n        try {\n            // source channel\n            raf = new RandomAccessFile(s, \"rw\");\n            srcChannel = raf.getChannel();\n\n            // Create channel on the destination\n            fos = new FileOutputStream(d);\n            dstChannel = fos.getChannel();\n\n            try {\n                if (!noLock) {\n                    srcChannel.lock();\n                } else {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \" [ Utils ] [ copyFile2File ] not taking locks for: \" + s);\n                    }\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Unable to take source file (\" + s\n                        + \") lock. Will continue without lock taken. Cause: \", t);\n            }\n            try {\n                if (!noLock) {\n                    dstChannel.lock();\n                } else {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \" [ Utils ] [ copyFile2File ] not taking locks for: \" + d);\n                    }\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Unable to take destination file (\" + d\n                        + \") lock. Will continue without lock taken. Cause: \", t);\n            }\n\n            // Copy file contents from source to destination - ZERO copy on most OSes!\n            final long tr = dstChannel.transferFrom(srcChannel, 0, srcChannel.size());\n\n            long ss = srcChannel.size();\n            long ds = dstChannel.size();\n\n            // dummy check - don't know what happens if disk is full\n            if ((ss != ds) || (ss != tr)) {\n                throw new IOException(\"Different size for sourceFile [ \" + s + \" ] DestinationFileSize [ \" + d\n                        + \" ] Transferred [ \" + tr + \" ] \");\n            }\n        } finally {\n            closeIgnoringExceptions(srcChannel);\n            closeIgnoringExceptions(dstChannel);\n            closeIgnoringExceptions(raf);\n            closeIgnoringExceptions(fos);\n        }\n    }\n\n    /**\n     * fills an array of File objects based on a list of files and directories\n     */\n    public static void getRecursiveFiles(String fileName, String remappedFileName, List<String> allFiles,\n                                         List<String> allRemappedFiles) throws Exception {\n\n        if (allFiles == null) {\n            throw new NullPointerException(\"File list is null\");\n        }\n        File file = new File(fileName);\n        if (file.exists() && file.canRead()) {\n            if (file.isFile()) {\n                allFiles.add(fileName);\n                allRemappedFiles.add(remappedFileName);\n            } else if (file.isDirectory()) {\n                String[] listContents = file.list();\n                if ((listContents != null) && (listContents.length > 0)) {\n                    for (String subFile : listContents) {\n                        if (remappedFileName != null) {\n                            getRecursiveFiles(fileName + File.separator + subFile, remappedFileName + File.separator\n                                    + subFile, allFiles, allRemappedFiles);\n                        } else {\n                            getRecursiveFiles(fileName + File.separator + subFile, null, allFiles, allRemappedFiles);\n                        }\n                    }\n                }\n            } else {// any other special device: e.g. /dev/zero, /dev/null :)\n                allFiles.add(fileName);\n                allRemappedFiles.add(remappedFileName);\n            }\n        }\n    }\n\n    /**\n     * Helper method to close a {@link FDTCloseable} ignoring eventual exceptions\n     *\n     * @param closeable to be closed\n     */\n    public static void closeIgnoringExceptions(FDTCloseable closeable, String downMessage, Throwable downCause) {\n        if (closeable != null) {\n            try {\n                closeable.close(downMessage, downCause);\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions closing FDTCloseable '\" + closeable + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    /**\n     * Helper method to close a {@link Closeable} ignoring eventual exceptions\n     *\n     * @param closeable to be closed\n     */\n    public static void closeIgnoringExceptions(Closeable closeable) {\n        if (closeable != null) {\n            try {\n                closeable.close();\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions closing Closeable '\" + closeable + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    /**\n     * Helper method to close a {@link Selector} ignoring eventual exceptions\n     *\n     * @param selector to be closed\n     */\n    public static void closeIgnoringExceptions(Selector selector) {\n        if (selector != null) {\n            try {\n                selector.close();\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions closing Selector '\" + selector + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    /**\n     * Helper method to close a {@link Socket} ignoring eventual exceptions\n     *\n     * @param socket to be closed\n     */\n    public static void closeIgnoringExceptions(Socket socket) {\n        if (socket != null) {\n            try {\n                socket.close();\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions closing Socket '\" + socket + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    public static void cancelFutureIgnoringException(Future<?> f, boolean mayInterruptIfRunning) {\n        if (f != null) {\n            try {\n                f.cancel(mayInterruptIfRunning);\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions canceling Future '\" + f + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    /**\n     * Helper method to close a {@link ServerSocket} ignoring eventual exceptions\n     *\n     * @param serverSocket to be closed\n     */\n    public static void closeIgnoringExceptions(ServerSocket serverSocket) {\n        if (serverSocket != null) {\n            try {\n                serverSocket.close();\n            } catch (Throwable ign) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Exceptions closing ServerSocket '\" + serverSocket + \"'. Cause: \", ign);\n                }\n            }\n        }\n    }\n\n    public static String toStringSelectionKey(final FDTSelectionKey fsk) {\n        if (fsk == null) {\n            return \" Null FDTSelectionKey ! \";\n        }\n        final StringBuilder sb = new StringBuilder(\"Socket \");\n\n        try {\n            final SocketChannel sc = fsk.channel();\n            final Selector sel = fsk.selector();\n\n            if (sc == null) {\n                sb.append(\" NULL! \");\n            } else {\n                sb.append(sc.socket());\n                if (sel == null) {\n                    sb.append(\" NULL SELECTOR! \");\n                } else {\n                    final SelectionKey sk = sc.keyFor(sel);\n                    if (sk == null) {\n                        sb.append(\" no such SelectionKey for selector! \");\n                    } else {\n                        sb.append(' ').append(toStringSelectionKey(sk));\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            sb.append(\" [ toStringSelectionKey ] Exception \").append(t);\n        }\n        return sb.toString();\n    }\n\n    private static String toStringSelectionKey(final SelectionKey sk) {\n        final StringBuilder sb = new StringBuilder(\"SelectionKey [ \");\n        if (sk.isValid()) {\n            sb.append(\"INVALID\");\n        } else {\n            sb.append(\"VALID\");\n            sb.append(\" :- interestOps \").append(toStringSelectionKeyOps(sk.interestOps()));\n            sb.append(\" :- readyOps\").append(toStringSelectionKeyOps(sk.readyOps()));\n        }\n        sb.append(\" ]\");\n        return sb.toString();\n    }\n\n    /**\n     * @param versionString1\n     * @param versionString2\n     * @return 0 if equals or both null, 1 if first is first version is greater, -1 otherwise\n     * @throws NullPointerException if one of the two params is null (XOR test).\n     * @see FDTVersion#compareTo(FDTVersion)\n     */\n    @SuppressWarnings(\"SameParameterValue\")\n    public static int compareVersions(final String versionString1, final String versionString2) {\n        if ((versionString1 == null) && (versionString2 == null)) {\n            return 0;\n        }\n\n        if ((versionString1 == null) || (versionString2 == null)) {\n            if (versionString1 == null) {\n                throw new NullPointerException(\"versionString1 is null\");\n            }\n\n            //noinspection ConstantConditions\n            if (versionString2 == null) {\n                throw new NullPointerException(\"versionString2 is null\");\n            }\n        }\n\n        return FDTVersion.fromVersionString(versionString1).compareTo(FDTVersion.fromVersionString(versionString2));\n    }\n\n    private static String toStringSelectionKeyOps(final int keyOps) {\n        final StringBuilder sb = new StringBuilder(\"{\");\n\n        boolean bAdded = false;\n        for (int i = 0; i < SELECTION_KEY_OPS_VALUES.length; i++) {\n            if ((keyOps & SELECTION_KEY_OPS_VALUES[i]) == SELECTION_KEY_OPS_VALUES[i]) {\n                if (bAdded) {\n                    sb.append('|');\n                } else {\n                    bAdded = true;\n                }\n\n                sb.append(' ').append(SELECTION_KEY_OPS_NAMES[i]).append(' ');\n            }\n        }\n\n        sb.append('}');\n        return sb.toString();\n    }\n\n    static String joinString(CharSequence delimiter, CharSequence... elements) {\n        StringBuilder sb = new StringBuilder();\n\n        if (elements.length > 0) {\n            sb.append(elements[0]);\n        }\n        for (int i = 1; i < elements.length; i++) {\n            sb.append(delimiter).append(elements[i]);\n        }\n\n        return sb.toString();\n    }\n\n    static InetAddress getLoopbackAddress() {\n        InetAddress localhost = null;\n\n        try {\n            byte[] address = {127, 0, 0, 1};  // 127.0.0.1\n            localhost = InetAddress.getByAddress(\"localhost\", address);\n        } catch (UnknownHostException ex) {\n            // do nothing\n        }\n\n        return localhost;\n    }\n\n    public static ArrayBlockingQueue<Integer> getTransportPortsValue(Map<String, Object> configMap, String key, int defaultPortNo) {\n        ArrayBlockingQueue<Integer> transportPorts = new ArrayBlockingQueue<>(10);\n        int i = 0;\n        Object obj = configMap.get(key);\n        if (obj == null || obj.toString().isEmpty()) {\n            transportPorts.add(defaultPortNo);\n            return transportPorts;\n        }\n        String tp = obj.toString();\n        StringTokenizer stk = new StringTokenizer(tp, \",\");\n        String s[] = new String[10];\n        while (stk.hasMoreTokens()) {\n            s[i] = stk.nextToken();\n            transportPorts.add(Integer.parseInt(s[i]));\n            i++;\n        }\n        return transportPorts;\n    }\n\n    private static void initLocalProps(String level, Properties localProps) {\n\n        FileInputStream fis = null;\n        File confFile = null;\n        try {\n            confFile = new File(\n                    System.getProperty(\"user.home\") + File.separator + \".fdt\" + File.separator + \"fdt.properties\");\n            if (level.contains(\"FINE\")) {\n                logger.info(\"Using local properties file: \" + confFile);\n            }\n            if (confFile.exists() && confFile.canRead()) {\n                fis = new FileInputStream(confFile);\n                localProps.load(fis);\n            }\n        } catch (Throwable t) {\n            if (confFile != null) {\n                if (level.contains(\"FINE\")) {\n                    System.err.println(\"Unable to read local configuration file \" + confFile);\n                    t.printStackTrace();\n                }\n            }\n        } finally {\n            Utils.closeIgnoringExceptions(fis);\n        }\n\n        if (level.contains(\"FINE\")) {\n            if (localProps.size() > 0) {\n                if (level.contains(\"FINER\")) {\n                    logger.info(\" LocalProperties loaded: \" + localProps);\n                }\n            } else {\n                logger.info(\"No local properties defined\");\n            }\n        }\n    }\n\n    public static void initLogger(String level, File logFile, Properties localProps) {\n        initLocalProps(level, localProps);\n        Properties loggingProps = new Properties();\n        loggingProps.putAll(localProps);\n\n        try {\n            if (!loggingProps.containsKey(\"handlers\")) {\n                loggingProps.put(\"handlers\", \"java.util.logging.ConsoleHandler\");\n                loggingProps.put(\"java.util.logging.ConsoleHandler.level\", \"FINEST\");\n                loggingProps.put(\"java.util.logging.ConsoleHandler.formatter\", \"java.util.logging.SimpleFormatter\");\n                loggingProps.put(\"java.util.logging.SimpleFormatter.format\", \"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n\");\n            }\n\n            if (logFile != null) {\n                if (loggingProps.contains(\"handlers\")) {\n                    loggingProps.remove(\"handlers\");\n                }\n\n                loggingProps.put(\"handlers\", \"java.util.logging.FileHandler,java.util.logging.ConsoleHandler\");\n                loggingProps.put(\"java.util.logging.ConsoleHandler.level\", \"FINEST\");\n                loggingProps.put(\"java.util.logging.ConsoleHandler.formatter\", \"java.util.logging.SimpleFormatter\");\n                loggingProps.put(\"java.util.logging.SimpleFormatter.format\", \"%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n\");\n                loggingProps.put(\"java.util.logging.FileHandler.level\", \"FINEST\");\n                loggingProps.put(\"java.util.logging.FileHandler.formatter\", \"java.util.logging.SimpleFormatter\");\n                loggingProps.put(\"java.util.logging.FileHandler.pattern\", \"\" + logFile);\n                loggingProps.put(\"java.util.logging.FileHandler.append\", \"true\");\n\n                System.setProperty(\"CustomLog\", \"true\");\n            }\n\n            if (!loggingProps.containsKey(\".level\")) {\n                loggingProps.put(\".level\", level);\n            }\n\n            if (level.contains(\"FINER\")) {\n                logger.info(\"\\n Logging props: \" + loggingProps);\n            }\n\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            loggingProps.store(baos, null);\n            LogManager.getLogManager().reset();\n            LogManager.getLogManager().readConfiguration(new ByteArrayInputStream(baos.toByteArray()));\n\n        } catch (Throwable t) {\n            System.err.println(\" Got exception setting the logging level \");\n            t.printStackTrace();\n        }\n    }\n\n    public static void waitAndWork(ExecutorService executor, ServerSocket ss, Selector sel, Config config) throws Exception {\n        if (config.isGSIModeEnabled()) {\n            FDTGSIServer gsiServer = new FDTGSIServer(config.getGSIPort());\n            gsiServer.start();\n            logger.log(Level.INFO, \"FDT started in GSI mode on port: \" + config.getGSIPort());\n        }\n        waitForTask(executor, ss, sel);\n\n        int transferPort = getFDTTransferPort(config);\n        if (transferPort > 0) {\n            final FDTServer theServer = new FDTServer(transferPort);\n            theServer.doWork();\n        } else {\n            logger.warning(\"There are no free transfer ports at this moment, please try again later\");\n            waitForTask(executor, ss, sel);\n        }\n    }\n\n    public static int getFDTTransferPort(Config config) throws Exception {\n        ControlChannel cc = new ControlChannel(config.getHostName(), config.getPort(), UUID.randomUUID(), FDTSessionManager.getInstance());\n        int transferPort = cc.sendTransferPortMessage(new CtrlMsg(CtrlMsg.REMOTE_TRANSFER_PORT, \"rtp\"));\n        // wait for remote config\n        logger.log(Level.INFO, \"Got transfer port: \" + config.getHostName() + \":\" + transferPort);\n        return transferPort;\n    }\n\n    private static void waitForTask(ExecutorService executor, ServerSocket ss, Selector sel) throws Exception {\n        try {\n\n            for (; ; ) {\n                final int count = sel.select(2000);\n\n                if (count == 0)\n                    continue;\n\n                Iterator<SelectionKey> it = sel.selectedKeys().iterator();\n                while (it.hasNext()) {\n                    final SelectionKey sk = it.next();\n                    it.remove();\n\n                    if (!sk.isValid())\n                        continue;// closed socket ?\n\n                    if (sk.isAcceptable()) {\n                        final ServerSocketChannel ssc = (ServerSocketChannel) sk.channel();\n                        final SocketChannel sc = ssc.accept();\n\n                        try {\n                            executor.execute(new AcceptableTask(sc));\n                        } catch (Throwable t) {\n                            StringBuilder sb = new StringBuilder();\n                            sb.append(\"[ FDT ] [ waitForTask ] got exception in while sumbiting the AcceptableTask for SocketChannel: \").append(sc);\n                            if (sc != null) {\n                                sb.append(\" Socket: \").append(sc.socket());\n                            }\n                            sb.append(\" Cause: \");\n                            logger.log(Level.WARNING, sb.toString(), t);\n                        }\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"[FDT] [ waitForTask ] Exception in main loop!\", t);\n            throw new Exception(t);\n        }\n\n    }\n\n    public static boolean isTransferPort(int localPort) {\n        return Config.getInstance().getRemoteTransferPorts().contains(localPort);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/common/usage",
    "content": "\nUsage: java -jar fdt.jar [ OPTIONS ]\n       java -jar fdt.jar [ OPTIONS ] -c <host> STANDALONE_ARGS\n       java -jar fdt.jar [ OPTIONS ] SCP_SYNTAX\n\n\nSTANDALONE_ARGS: [file1 ...]|[-fl <fileList>]\nSCP_SYNTAX: [-gsissh] [[user@][host1:]]file1 [[user@][host2:]]file2\n\nClient specific:\n   -c <host>\t\t connect to the specified <host>\n   \t\t\t If this parameter is missing FDT will become server\n   -d <destinationDir>\t The destination directory used to copy the files\n   -fl <fileList>\t a list of files (MUST containe one file per line)\n   -r\t\t\t Recursive. Searches for files in all specified \n   \t\t\t directories and subdirectories\n   -pull\t\t Pull Mode.The client will receive the data from\n   \t\t\t the server\n   -ss <windowSize>\t Set TCP SO_SND_BUFFER window size to windowSize\n   \t\t\t [K(ilo)|M(ega)] may be used as suffixes\n   -P <numberOfStreams>\t number of paralel streams(sockets) to use\n   \t\t\t Default is 4\n   -limit <rate>\t Restrict the transfer speed at the specified rate\n   \t\t\t [K(ilo)|M(ega)] may be used. If no suffix is specified\n   \t\t\t Bytes/s is considered to be the default.\n   -N\t\t\t disable Nagle's algorithm\n   -monID <monID>\t report session specific params with this monID\n   -gsissh\t\t uses GSI over SSH authentication. It is presumed that\n   \t\t\t the remote SSHD server supports GSI authentication\n   -sshp <remoteSSHPort> the (GSI) SSH port to connect to on the remote host.\n   \t\t\t This option is used only for SCP_SYNTAX for normal SSH\n   \t\t\t and GSI over SSH.\n   \t\t\t By default, the standard SSH port (22) will be used.\n   -sshKey <sshKey>\t Will try to use the ssh key specified by <sshKey>\n   \t\t\t By default, FDT will look for ssh keys in\n   \t\t\t $HOME/.ssh/id_dsa.fdt (DSA) and\n   \t\t\t $HOME/.ssh/id_rsa.fdt (RSA)\n   -shell <customShell>  By default /bin/bash is used, but if you are on \n                         something esoteric like a mainframe, you might have \n\t\t\t an alternate location for bash. \n\t\t\t i.e. - /rsusr/rocket/bin/bash\n\t-FDT_LISTEN <IP_ADDRESS> by default FDT is listening to all IP adresses.\n\t         This option tells FDT to listen only on specific IP address\n\nServer specific:\n   -S\t\t\t disable standalone mode; if specified, the server\n   \t\t\t will stop after the last client finishes\n   -bs <bufferSize>\t Size for the I/O buffers. [K(ilo)|M(ega)] may be used\n   \t\t\t as suffixes. The default is 1 MByte.\n   -f <allowedIPsList>\t A list of IP addresses allowed to connect to the server\n   \t\t\t Multiple IP addresses may be separated by ':'\n\nClient/Server:\n   -nettest\t\t Network test mode. The source and destination (-d)\n   \t\t\t options can be omitted. If present, will be ignored! \n   \t\t\t FDT will act only as a network benchmark tool.\n   \t\t\t If the server is started with this flag *ALL* network\n   \t\t\t transfers will be considered benchmark transfers!\n   -nolock\t\t Disables file locking on the writer side. Default this\n\t\t\t flag is false, which means that FDT tries to aquire\n\t\t\t an exclusive file lock for the file which is written.\n   -notmp\t\t Disables intermediate hidden file creation. Without \n   \t\t\t this flag FDT transfers a /localDir/fileName to an \n\t\t\t intermediate hidden file /destinationDir/.fileName \n\t\t\t and, after the content of the file is transfered,\n\t\t\t it moves the file to /destinationDir/fileName. \n   -gsi\t\t\t Enables the GSI authentication scheme. It must be used\n   \t\t\t for both the FDT client and server.If the flag is\n   \t\t\t enabled, the FDT server will accept only GSI\n   \t\t\t authenticated FDT clients.\n   -p <portNumber>\t port number to listen on/connect to (server/client)\n   \t\t\t or to connect to for the client.Default is 54321.\n   -gsip <GSICtrlPort>\t the GSI control port to listen on/connect to\n   \t\t\t (server/client) for GSI authentication. In the GSI\n   \t\t\t mode FDT will use two ports: one for control(-gsip)\n   \t\t\t and one for the data channels(-p). Default value for\n   \t\t\t GSICtrlPort is 54320.\n   -preFilters f1,..,fn\t User defined pre-processing filters. The\n   \t\t\t preProcessing filters must be in the classpath and\n   \t\t\t may be cascadated. f1,...,fn are java classes, which\n   \t\t\t will be loaded in the preProcessing phase.They must be\n   \t\t\t specified in the FDT \"sender\" command line.\n   -postFilters f1,..,fn User defined post-processing filters. The\n   \t\t\t postProcessing filters must be in the classpath and\n   \t\t\t may be cascadated. f1,...,fn are java classes, which\n   \t\t\t will be loaded in the postProcessing phase. They must\n   \t\t\t be specified in the FDT \"receiver\" command line.\n   -wCount <wCount>\t number of writer threads per partition.\n   \t\t\t Default wCount=1.\n   -rCount <rCount>\t number of reader threads per partition.\n   \t\t\t Default rCount=1.\n   -md5\t\t\t enables MD5 checksum for every file transfered.\n   \t\t\t It must be specified in the \"sender\" and the\n   \t\t\t \"receiver\" will print am `md5sum`-like list at the end\n   \t\t\t of the transfer. Default is the checksum is disabled.\n   -(n)bio\t\t (Non-)Blocking I/O mode. In the blocking mode every\n   \t\t\t stream(socket) will use a thread to perform the I/O.\n   \t\t\t By default (since 0.9.20) blocking mode is used\n   -iof <iof>\t\t Non blocking I/O retry factor. Repeat every\n   \t\t\t read/write operation (non-blocking I/O mode only),\n   \t\t\t which returns 0, up to <iof> times before waiting for\n   \t\t\t I/O readiness.Default is 1, which should be ok, but \n   \t\t\t values of 2 or 3 may show slight gains in network I/O\n   \t\t\t performance. Usual values are between 1 and 4.\n   \t\t\t Higher values are not recommended because the gain\n   \t\t\t will be zero while the CPU System will increase\n   -printStats\t\t Print statistics for buffer pools, sessions, etc\n   -v\t\t\t Verbose mode. Multiple 'v'-s may be used to increase\n   \t\t\t the verbosity level. Maximum level is 3 (-vvv), which\n   \t\t\t corresponds to Level.FINEST for the standard Java\n   \t\t\t logging system used by FDT.\n\nMiscellaneous:\n   -noupdates\t\t Do not check for updates.\n   -silent\t\t Do not ask for confirmation if updates are available.\n   -u, -update,--update\t Update the fdt.jar, if a newer version\n   \t\t\t is available on the update server and exits\n   -V, -version,\t print version information and quit\n   --version\n   -h, -help, --help\t print this help message and quit\n\nContact: support-fdt@monalisa.cern.ch\n"
  },
  {
    "path": "src/lia/util/net/copy/Accountable.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\n/**\n * Simple interface implemented by all the FDT classes which may have something\n * to, or that, count :)\n *\n * @author ramiro\n */\npublic interface Accountable {\n\n    public long getUtilBytes();\n\n    public long getTotalBytes();\n\n    public long getSize();\n\n    public long addAndGetUtilBytes(long delta);\n\n    public long addAndGetTotalBytes(long delta);\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/AccountableEntity.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Default implementation for {@link Accountable}\n *\n * @author ramiro\n */\npublic abstract class AccountableEntity implements Accountable {\n\n    AtomicLong totalProcessedBytes;\n    AtomicLong totalUtilBytes;\n\n    public AccountableEntity() {\n        this(0, 0);\n    }\n\n    public AccountableEntity(long initialProcessedBytes, long initialUtilBytes) {\n        totalProcessedBytes = new AtomicLong(initialProcessedBytes);\n        totalUtilBytes = new AtomicLong(initialUtilBytes);\n    }\n\n    public long addAndGetTotalBytes(long delta) {\n        return totalProcessedBytes.addAndGet(delta);\n    }\n\n    public long addAndGetUtilBytes(long delta) {\n        return totalUtilBytes.addAndGet(delta);\n    }\n\n    public long getTotalBytes() {\n        return totalProcessedBytes.get();\n    }\n\n    public long getUtilBytes() {\n        return totalUtilBytes.get();\n    }\n\n    public abstract long getSize();\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDT.java",
    "content": "package lia.util.net.copy;\n\nimport apmon.ApMon;\nimport lia.util.net.common.*;\nimport lia.util.net.copy.monitoring.ApMonReportingTask;\nimport lia.util.net.copy.monitoring.ConsoleReportingTask;\nimport lia.util.net.copy.monitoring.FDTInternalMonitoringTask;\nimport lia.util.net.copy.monitoring.lisa.LISAReportingTask;\nimport lia.util.net.copy.transport.*;\nimport lia.util.net.copy.transport.internal.SelectionManager;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The \"main\" class ... Everything will start from here, more or less\n * <p>\n * Due to Java checks the app entry point is {@link FDTMain}\n *\n * @author ramiro\n */\npublic class FDT {\n\n    public static final String MONALISA2_CERN_CH = \"monalisa2.cern.ch:8884\";\n    public static final String RELEASE_DATE = Config.FDT_RELEASE_DATE.replaceAll(\"-\", \"\");\n    public static final String FDT_FULL_VERSION = Config.FDT_FULL_VERSION + \"-\" + RELEASE_DATE + Config.FDT_RELEASE_TIME;\n    /**\n     * two weeks between checking for updates\n     */\n    public static final long UPDATE_PERIOD = 2 * 24 * 3600 * 1000;\n    private static final String name = \"FDT\";\n    private static final Logger logger = Logger.getLogger(FDT.class.getName());\n    private static String UPDATE_OWNER = \"fast-data-transfer\";\n    private static String UPDATE_REPO = \"fdt\";\n    public static String UPDATE_URL = \"https://api.github.com/repos/\" + UPDATE_OWNER + \"/\" + UPDATE_REPO + \"/releases\";\n    private static Config config;\n\n    private static Properties localProps = new Properties();\n\n    FDT() throws Exception {\n        String monitor = config.getMonitor();\n        switch (monitor) {\n            case Config.APMON:\n                initApMon();\n                break;\n            case Config.OPENTSDB:\n                initOpenTSDB(config);\n                break;\n            default:\n                break;\n        }\n\n\n        scheduleReportingTasks();\n\n        if (config.isCoordinatorMode()) {\n            ControlChannel cc = new ControlChannel(config.getHostName(), config.getPort(), UUID.randomUUID(), FDTSessionManager.getInstance());\n            String sessionID = cc.sendCoordinatorMessage(new CtrlMsg(CtrlMsg.THIRD_PARTY_COPY, new FDTSessionConfigMsg(config)));\n            if (sessionID.equals(\"-1\")) {\n                logger.log(Level.WARNING, \"Message sent to: \" + config.getHostName() + \":\" + config.getPort() + \" but no free transfer ports available\");\n            } else {\n                logger.log(Level.INFO, \"Message sent to: \" + config.getHostName() + \":\" + config.getPort() + \" Remote Job Session ID: \" + sessionID);\n            }\n            System.exit(0);\n        } else if (config.isListFilesMode()) {\n            ControlChannel cc = new ControlChannel(config.getHostName(), config.getPort(), UUID.randomUUID(), FDTSessionManager.getInstance());\n            List<String> filesInDir = cc.sendListFilesMessage(new CtrlMsg(CtrlMsg.LIST_FILES, new FDTListFilesMsg(config.getListFilesFrom())));\n            logger.log(Level.INFO, \"Message sent to: \" + config.getHostName() + \":\" + config.getPort());\n            printOutResults(filesInDir);\n            System.exit(0);\n\n        } else if (config.isThirdPartyCopyAgent()) {\n            waitForTask();\n        } else {\n            if (config.getHostName() != null) { // role == client\n                config.setRemoteTransferPort(Utils.getFDTTransferPort(config));\n                try {\n                    FDTSessionManager.getInstance().addFDTClientSession(config.getRemoteTransferPort());\n                } catch (FileNotFoundException ex) {\n                    ControlChannel cc = new ControlChannel(config.getHostName(), config.getPort(), UUID.randomUUID(), FDTSessionManager.getInstance());\n                    cc.sendCtrlMessage(new CtrlMsg(CtrlMsg.FILE_NOT_FOUND, ex.getMessage()));\n                }\n            } else { // is server\n                if (!DirectByteBufferPool.initInstance(config.getByteBufferSize(), Config.getMaxTakePollIter())) {\n                    // this is really wrong ... I cannot be already initialized\n                    throw new FDTProcolException(\"The buffer pool cannot be already initialized\");\n                }\n                final FDTServer theServer = new FDTServer(config.getPort());\n                theServer.doWork();\n            }\n        }\n    }\n\n    public static void initOpenTSDB(Config config) throws Exception {\n\n        config.initOpenTSDBMonitorClient();\n        ApMon apmon = null;\n        long lStart = System.currentTimeMillis();\n        try {\n            Vector<String> vHosts = new Vector<>();\n            Vector<Integer> vPorts = new Vector<>();\n            //dummy host\n            vHosts.add(\"127.0.0.1\");\n            vPorts.add(12345);\n            ApMon.setLogLevel(\"WARNING\");\n            apmon = new ApMon(vHosts, vPorts);\n            apmon.setConfRecheck(false, -1);\n            apmon.setGenMonitoring(true, 20);\n            String cluster_name;\n            String node_name;\n            if (config.getHostName() != null) {\n                cluster_name = \"Clients\";\n                node_name = config.getHostName();\n            } else {// server\n                cluster_name = \"Servers\";\n                node_name = apmon.getMyHostname();\n            }\n            apmon.setMonitorClusterNode(cluster_name, node_name);\n            apmon.setSysMonitoring(true, 10);\n        } catch (Throwable ex) {\n            logger.log(Level.WARNING, \"Error initializing ApMon engine.\", ex);\n        } finally {\n            Utils.initApMonInstance(apmon);\n        }\n\n        try {\n            if (Utils.getApMon() != null) {\n                ApMonReportingTask apmrt = new ApMonReportingTask();\n                Utils.getMonitoringExecService().scheduleWithFixedDelay(apmrt, 1,\n                        config.getApMonReportingInterval(), TimeUnit.SECONDS);\n            } else {\n                logger.log(Level.WARNING, \"Cannot start ApMonReportingTask because apMon is null!\");\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Cannot start ApMonReportingTask because got Exception.\", t);\n        }\n\n        long lEnd = System.currentTimeMillis();\n        logger.info(\"ApMon for OpenTSDB initialization took \" + (lEnd - lStart) + \" ms\");\n    }\n\n\n    private static void scheduleReportingTasks() {\n        Utils.getMonitoringExecService().scheduleWithFixedDelay(FDTInternalMonitoringTask.getInstance(), 1, 5,\n                TimeUnit.SECONDS);\n        final long reportingTaskDelay = config.getReportingTaskDelay();\n        if (reportingTaskDelay > 0) {\n            Utils.getMonitoringExecService().scheduleWithFixedDelay(ConsoleReportingTask.getInstance(), 0,\n                    reportingTaskDelay, TimeUnit.SECONDS);\n        }\n    }\n\n    private static void printOutResults(List<String> filesInDir) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"\\r\\n\");\n        for (String entry : filesInDir) {\n            sb.append(entry);\n            sb.append(\"\\r\\n\");\n        }\n        String files = sb.toString();\n        logger.info(files);\n    }\n\n    private static void printHelp() {\n        logger.log(Level.INFO, Config.getUsage());\n    }\n\n    private static void printVersion() {\n        logger.info(name + ' ' + FDT_FULL_VERSION);\n        logger.info(\"Contact: support-fdt@monalisa.cern.ch\");\n    }\n\n    private static int doWork() {\n\n        Exception e = null;\n        FDTSessionManager fdtSessionManager = FDTSessionManager.getInstance();\n\n        try {\n            for (; ; ) {\n                try {\n                    Thread.sleep(1000);\n                    if (config.getHostName() != null && fdtSessionManager.isInited()) {\n                        if (fdtSessionManager.sessionsNumber() == 0) {\n                            break;\n                        }\n\n                        try {\n                            fdtSessionManager.awaitTermination();\n                        } catch (InterruptedException ie) {\n                            Thread.interrupted();\n                        }\n                    } else {\n                        if (!config.isStandAlone() && fdtSessionManager.isInited()\n                                && fdtSessionManager.sessionsNumber() == 0 && !config.isThirdPartyCopyAgent()) {\n                            SelectionManager.getInstance().stopIt();\n                            logger.info(\n                                    \"Server started with -S flag set and all the sessions have finished ... FDT will stop now\");\n                            break;\n                        }\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"FDT Got exception in main loop\", t);\n                }\n            }\n        } catch (Exception ex) {\n            e = ex;\n        } finally {\n            try {\n                logger.info(\" [ \" + new Date().toString()\n                        + \" ] - GracefulStopper hook started ... Waiting for the cleanup to finish\");\n\n                AtomicReference<GracefulStopper> stopper = new AtomicReference<>(new GracefulStopper());\n\n                // it will be the last in the queue ;)\n                stopper.get().close(null, e);\n\n                while (!stopper.get().internalClosed) {\n                    synchronized (stopper.get()) {\n                        if (stopper.get().internalClosed) {\n                            break;\n                        }\n                        try {\n                            stopper.get().wait();\n                        } catch (Throwable t) {\n                            t.printStackTrace();\n                        }\n                    }\n                }\n                logger.info(\" [ \" + new Date().toString() + \" ]  - GracefulStopper hook finished!\");\n            } catch (Throwable gExc) {\n                logger.log(Level.WARNING, \" [GracefulStopper] Got exception stopper\", gExc);\n            }\n        }\n\n        final Throwable tExit = fdtSessionManager.getLasDownCause();\n        final String mExit = fdtSessionManager.getLasDownMessage();\n        if (tExit != null || mExit != null) {\n            logger.log(Level.WARNING, \"\\n [ \" + new Date().toString() + \" ]  FDT Session finished with errors: \");\n            if (mExit != null) {\n                logger.log(Level.WARNING, mExit + '\\n');\n            }\n\n            if (tExit != null) {\n                logger.log(Level.WARNING, Utils.getStackTrace(tExit) + '\\n');\n            }\n\n            return 1;\n        }\n\n        logger.info(\"\\n [ \" + new Date().toString() + \" ]  FDT Session finished OK.\\n\");\n        return 0;\n    }\n\n    private static void processSCPSyntax(String[] args) throws Exception {\n        int iTransferConfiguration = config.getSSHConfig();\n        if (iTransferConfiguration > 0) {\n            final int sshPort = config.getSSHPort();\n\n            switch (iTransferConfiguration) {\n                case Config.SSH_REMOTE_SERVER_LOCAL_CLIENT_PUSH:\n                    sshRemoteServerLocalClientPush(sshPort);\n                    break;\n                case Config.SSH_REMOTE_SERVER_LOCAL_CLIENT_PULL:\n                    sshRemoteServerLocalClientPull(sshPort);\n                    break;\n                case Config.SSH_REMOTE_SERVER_REMOTE_CLIENT_PUSH:\n                    sshRemoteServerAndClientPush(args, sshPort);\n                    break;\n                default:\n                    break;\n            }\n        }\n    }\n\n    private static void sshRemoteServerLocalClientPush(int sshPort) throws Exception {\n        ControlStream sshConn;\n        String localAddresses;\n        StringBuilder remoteCmd;\n        String remoteCustomShell;\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\"[SSH Mode] SSH_REMOTE_SERVER_LOCAL_CLIENT_PUSH. Remote ssh port: \" + sshPort);\n        }\n        try {// here we can have some class-not-found exceptions if GSI libraries are not loaded\n            sshConn = config.isGSISSHModeEnabled() ? //\n                    new GSISSHControlStream(config.getHostName(),\n                            config.getDestinationUser(), sshPort)\n                    : //\n                    new SSHControlStream(config.getHostName(), config.getDestinationUser(), sshPort);\n        } catch (NoClassDefFoundError t) {\n            throw new Exception(\"GSI libraries not loaded. You should set CLASSPATH accordingly!\");\n        }\n        sshConn.connect();\n        localAddresses = config.getLocalAddresses();\n        // append the required options to the configurable java command\n        remoteCmd = new StringBuilder(config.getRemoteCommand() + \" -p \" + config.getPort() + \" -noupdates -silent -S -f \"\n                + localAddresses);\n        remoteCustomShell = config.getCustomShell();\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] Starting FDT server over SSH using [ \" + remoteCmd + \" ]\");\n        }\n        sshConn.startProgram(remoteCmd.toString(), remoteCustomShell.toString());\n        sshConn.waitForControlMessage(\"READY\");\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] FDT server successfully started on [ \" + config.getHostName() + \" ]\");\n        }\n    }\n\n    private static void sshRemoteServerLocalClientPull(int sshPort) throws Exception {\n        String[] clients;\n        ControlStream sshConn;\n        String localAddresses;\n        StringBuilder remoteCmd;\n        String remoteCustomShell;\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\"[SSH Mode] SSH_REMOTE_SERVER_LOCAL_CLIENT_PULL. Remote ssh port: \" + sshPort);\n        }\n        // the host running the FDT server is the source in this case\n        String remoteServerHost = config.getSourceHosts()[0];\n        String remoteServerUsername;\n        clients = config.getSourceUsers();\n        if (clients != null && clients.length > 0 && clients[0] != null) {\n            remoteServerUsername = clients[0];\n        } else {\n            remoteServerUsername = System.getProperty(\"user.name\", \"root\");\n        }\n        // update the local client parameters\n        config.setPullMode(true);\n        config.setHostName(remoteServerHost);\n\n        try {// here we can have some class-not-found exceptions if GSI libraries are not loaded\n            sshConn = config.isGSISSHModeEnabled()\n                    ? new GSISSHControlStream(remoteServerHost, remoteServerUsername,\n                    sshPort)\n                    : new SSHControlStream(remoteServerHost, remoteServerUsername, sshPort);\n        } catch (NoClassDefFoundError t) {\n            throw new Exception(\"GSI libraries not loaded. You should set CLASSPATH accordingly!\");\n        }\n        sshConn.connect();\n        localAddresses = config.getLocalAddresses();\n        // append the required options to the configurable java command\n        remoteCmd = new StringBuilder(config.getRemoteCommand() + \" -p \" + config.getPort() + \" -noupdates -silent -S -f \"\n                + localAddresses);\n        remoteCustomShell = config.getCustomShell();\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] Starting FDT server over SSH using [ \" + remoteCmd + \" ]\");\n        }\n        sshConn.startProgram(remoteCmd.toString(), remoteCustomShell.toString());\n        sshConn.waitForControlMessage(\"READY\");\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] FDT server successfully started on [ \" + remoteServerHost + \" ]\");\n        }\n    }\n\n    private static void sshRemoteServerAndClientPush(String[] args, int sshPort) throws Exception {\n        ControlStream sshConn;\n        StringBuilder remoteCmd;\n        String remoteCustomShell;\n        String[] clients;\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\"[SSH Mode] SSH_REMOTE_SERVER_REMOTE_CLIENT_PUSH. Remote ssh port: \" + sshPort);\n        }\n        // the host starting the fdt client\n        final String clientHost = config.getSourceHosts()[0];\n        // start FDT Server\n        try {// here we can have some class-not-found exceptions if GSI libraries are not loaded\n            sshConn = config.isGSISSHModeEnabled()\n                    ? new GSISSHControlStream(config.getHostName(),\n                    config.getDestinationUser(), sshPort)\n                    : new SSHControlStream(config.getHostName(), config.getDestinationUser(), sshPort);\n        } catch (NoClassDefFoundError t) {\n            throw new Exception(\"GSI libraries not loaded. You should set CLASSPATH accordingly!\");\n        }\n        // append the required options to the configurable java command\n        remoteCmd = new StringBuilder(config.getRemoteCommand() + \" -p \" + config.getPort() + \" -noupdates -silent -S -f \"\n                + clientHost);\n        remoteCustomShell = config.getCustomShell();\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] Starting remote FDT server over SSH using [ \" + remoteCmd + \" ]\");\n        }\n        sshConn.startProgram(remoteCmd.toString(), remoteCustomShell.toString());\n        sshConn.waitForControlMessage(\"READY\");\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] FDT server successfully started on [ \" + config.getHostName() + \" ]\");\n        }\n        // server ok\n\n        // start FDT client\n        String clientUser;\n        clients = config.getSourceUsers();\n        if (clients != null && clients.length > 0 && clients[0] != null) {\n            clientUser = clients[0];\n        } else {\n            clientUser = System.getProperty(\"user.name\", \"root\");\n        }\n\n        try {// here we can have some class-not-found exceptions if GSI libraries are not loaded\n            sshConn = config.isGSISSHModeEnabled()\n                    ? new GSISSHControlStream(clientHost, clientUser, sshPort)\n                    : new SSHControlStream(clientHost, clientUser, sshPort);\n        } catch (NoClassDefFoundError t) {\n            throw new Exception(\"GSI libraries not loaded. You should set CLASSPATH accordingly!\");\n        }\n        remoteCmd = new StringBuilder(config.getRemoteCommand());\n        for (String arg : args) {\n            if (arg.indexOf(':') < 0) {\n                remoteCmd.append(' ').append(arg);\n            }\n        }\n        remoteCmd.append(\" -c \").append(config.getHostName());\n        remoteCmd.append(\" -d \").append(config.getDestinationDir());\n        String[] files = (String[]) config.getConfigMap().get(\"Files\");\n        remoteCmd.append(' ').append(files[0]);\n        if (logger.isLoggable(Level.FINE)) {\n            logger.fine(\" [ CONFIG ] Starting FDT client over SSH using [ \" + remoteCmd + \" ]\");\n        }\n        remoteCustomShell = config.getCustomShell();\n        sshConn.startProgram(remoteCmd.toString(), remoteCustomShell.toString());\n        // wait for client termination or forced exit\n        sshConn.waitForControlMessage(\"DONE\", true);\n        // after the remote client finished, our 'proxy' program should also exit\n        // maybe we should change this 'exit' with some method return code\n        System.exit(0);\n    }\n\n    private static void initManagement() throws Exception {\n        // not there yet\n    }\n\n    // the one and only entry point\n    public static void main(String[] args) throws Exception {\n        // Init the logging\n        String logLevel = initLogging(args);\n\n        Map<String, Object> argsMap = Utils.parseArguments(args, Config.SINGLE_CMDLINE_ARGS);\n\n        checkMainParams(argsMap);\n\n        final boolean noLock = checkAdditionalParams(argsMap);\n\n        updateOrSkip(logLevel, argsMap, noLock);\n\n        logger.info(\"\\n\\n\" + name + \" [ \" + FDT_FULL_VERSION + \" ] STARTED ... \\n\\n\");\n\n        initConfig(argsMap, logLevel);\n\n        if (!config.isCoordinatorMode() || !config.isRetrievingLogFile()) {\n            logger.info(\"FDT uses\" + ((!config.isBlocking()) ? \" *non-\" : \" *\") + \"blocking* I/O mode.\");\n        }\n\n        processSCPSyntax(args);\n\n        HeaderBufferPool.initInstance();\n\n        if (!config.isLisaDisabled()) {\n            LISAReportingTask lrt = LISAReportingTask.initInstance(config.getLisaHost(), config.getLisaPort());\n            Utils.getMonitoringExecService().scheduleWithFixedDelay(lrt, 1, config.getLisaReportingInterval(),\n                    TimeUnit.SECONDS);\n        }\n\n        try {\n            new FDT();\n            initManagement();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Failed to instantiate FDT\", t);\n            System.exit(1);\n        }\n\n        final int exitCode = FDT.doWork();\n\n        Utils.getMonitoringExecService().shutdownNow();\n        try {\n            if (config.massStorageType() != null && config.massStorageType().equals(\"dcache\")) {\n                final FileChannelProviderFactory fcpf = config.getFileChannelProviderFactory();\n                if (fcpf instanceof FDTCloseable) {\n                    ((FDTCloseable) fcpf).close(null, null);\n                }\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"FDT got exception trying to close the dCapLayer. Cause:\", t);\n            System.exit(2502);\n        }\n\n        System.exit(exitCode);\n    }\n\n    private static boolean checkAdditionalParams(Map<String, Object> argsMap) throws Exception {\n        final boolean noLock = argsMap.get(\"-nolock\") != null || argsMap.get(\"-nolocks\") != null;\n        if (argsMap.get(\"-h\") != null || argsMap.get(\"-H\") != null || argsMap.get(\"-help\") != null\n                || argsMap.get(\"--help\") != null) {\n            printHelp();\n            System.exit(0);\n        } else if (argsMap.get(\"-V\") != null || argsMap.get(\"--version\") != null || argsMap.get(\"-version\") != null) {\n            printVersion();\n            System.exit(0);\n        } else if (argsMap.get(\"-u\") != null || argsMap.get(\"-U\") != null || argsMap.get(\"-update\") != null\n                || argsMap.get(\"--update\") != null) {\n            updateIfAvailable(argsMap, noLock);\n        }\n        return noLock;\n    }\n\n    private static void initConfig(Map<String, Object> argsMap, String logLevel) {\n        try {\n            Config.initInstance(argsMap);\n        } catch (InvalidFDTParameterException e) {\n            logger.log(Level.WARNING, \"Invalid parameters supplied: \" + e.getMessage(), e);\n            System.exit(1);\n        } catch (Throwable t1) {\n            logger.log(Level.WARNING, \"got exception parsing command args\", t1);\n            System.exit(1);\n        }\n        config = Config.getInstance();\n        config.setLogLevel(logLevel);\n    }\n\n    private static void updateOrSkip(String logLevel, Map<String, Object> argsMap, boolean noLock) {\n        if (argsMap.get(\"-noupdates\") == null) {\n            final Object urlS = argsMap.get(\"-U\");\n            String updateURL = UPDATE_URL;\n\n            if (urlS != null && urlS instanceof String) {\n                updateURL = (String) urlS;\n                if (updateURL.length() == 0) {\n                    updateURL = UPDATE_URL;\n                }\n            }\n            try {\n                if (Utils.checkForUpdate(FDT_FULL_VERSION, updateURL, noLock)) {\n                    if (argsMap.get(\"-silent\") == null) {\n                        System.out.print(\n                                \"\\n\\nAn update is available ... Do you want to upgrade to the new version? [Y/n]\");\n                        char car = (char) System.in.read();\n                        logger.info(\"\\n\");\n                        if (car == 'Y' || car == 'y' || car == '\\n' || car == '\\r') {\n                            System.out.print(\"\\nTrying to update FDT to the new version ... \");\n                            if (Utils.updateFDT(FDT_FULL_VERSION, updateURL, true, noLock)) {\n                                // Just print the current version ...\n                                logger.info(\"\\nThe update finished successfully\\n\");\n                                System.exit(0);\n                            } else {\n                                logger.info(\"\\nNo updates available\\n\");\n                                System.exit(100);\n                            }\n                        }\n                    }\n                }\n            } catch (Throwable t) {\n                logger.info(\"Got exception checking for updates: \" + t.getCause());\n                if (logLevel.startsWith(\"FIN\")) {\n                    t.printStackTrace();\n                }\n            }\n        }\n    }\n\n    private static void updateIfAvailable(Map<String, Object> argsMap, boolean noLock) throws Exception {\n        final Object urlS = argsMap.get(\"-U\");\n        String updateURL = UPDATE_URL;\n\n        if (urlS != null && urlS instanceof String) {\n            updateURL = (String) urlS;\n            if (updateURL.length() == 0) {\n                updateURL = UPDATE_URL;\n            }\n        }\n\n        if (Utils.updateFDT(FDT_FULL_VERSION, updateURL, true, noLock)) {\n            // Just print the current version ...\n            logger.info(\"\\nThe update finished successfully\\n\");\n            System.exit(0);\n        } else {\n            logger.info(\"\\nNo updates available\\n\");\n            System.exit(100);\n        }\n    }\n\n    private static void checkMainParams(Map<String, Object> argsMap) {\n        if (argsMap.get(\"-c\") != null) {\n            if (argsMap.get(\"-d\") == null && argsMap.get(\"-nettest\") == null && argsMap.get(\"-ls\") == null) {\n                throw new IllegalArgumentException(\"No destination specified\");\n            }\n\n            @SuppressWarnings(\"unchecked\") final List<String> lParams = (List<String>) argsMap.get(\"LastParams\");\n\n            if ((argsMap.get(\"-nettest\") == null && argsMap.get(\"-fl\") == null\n                    && (lParams == null || lParams.size() == 0) && argsMap.get(\"Files\") == null)\n                    && argsMap.get(\"-sID\") == null && argsMap.get(\"-ls\") == null) {\n                throw new IllegalArgumentException(\"No source specified\");\n            }\n        }\n    }\n\n    private static String initLogging(String[] args) throws IOException {\n        String logLevel = null;\n        File logFile = null;\n        for (int i = 0; i < args.length; i++) {\n            if (logLevel == null) {\n                if (args[i].equals(\"-v\")) {\n                    logLevel = \"FINE\";\n                }\n\n                if (args[i].equals(\"-vv\")) {\n                    logLevel = \"FINER\";\n                }\n\n                if (args[i].equals(\"-vvv\")) {\n                    logLevel = \"FINEST\";\n                }\n\n                if (logFile == null) {\n                    if (args[i].equals(\"-log\")) {\n                        if (i >= args.length - 1) {\n                            throw new IllegalArgumentException(\"The -log parameter expects a file path\");\n                        }\n\n                        final String logPathParam = args[i + 1];\n                        if (logPathParam.startsWith(\"-\")) {\n                            throw new IllegalArgumentException(\n                                    \"The -log parameter expects a file path which does not start with '-'\");\n                        }\n\n                        //Java 6 still to be used for a while, will take it down next year ...\n                        final File logF = new File(logPathParam);\n                        final File logFParent = logF.getParentFile();\n                        if (logFParent != null && !logFParent.exists()) {\n                            try {\n                                final boolean mkdirsResult = logFParent.mkdirs();\n                                if (!mkdirsResult) {\n                                    throw new IllegalArgumentException(\"Unable to create parent dirs for log file: '\"\n                                            + logFParent + \"' OS syscall failed\");\n                                }\n                            } catch (Throwable t) {\n                                throw new IllegalArgumentException(\n                                        \"Unable to create parent dirs for log file: '\" + logFParent + \"' Cause:\", t);\n                            }\n                        }\n\n                        if (logF.exists()) {\n                            if (!logF.canWrite()) {\n                                throw new IOException(\n                                        \"The provided log file: '\" + logF + \"' exists but is not writable!\");\n                            }\n                        } else {\n                            final boolean createFileResult = logF.createNewFile();\n                            if (!createFileResult) {\n                                throw new IOException(\"The provided log file: '\" + logF + \"' cannot be created!\");\n                            }\n                        }\n\n                        //finally all looks good for now\n                        logFile = logF;\n                    }\n                }\n            }\n        }\n\n        if (logLevel == null) {\n            logLevel = \"INFO\";\n        }\n\n        if (logLevel.startsWith(\"FIN\")) {\n            logger.info(\" LogLevel: \" + logLevel);\n        }\n        Utils.initLogger(logLevel, logFile, localProps);\n        return logLevel;\n    }\n\n    private void waitForTask() throws Exception {\n        if (!DirectByteBufferPool.initInstance(config.getByteBufferSize(), Config.getMaxTakePollIter())) {\n            // this is really wrong ... It cannot be already initialized\n            throw new FDTProcolException(\"The buffer pool cannot be already initialized\");\n        }\n\n        ExecutorService executor = null;\n        ServerSocketChannel ssc = null;\n        ServerSocket ss = null;\n        Selector sel = null;\n        try {\n            executor = Utils.getStandardExecService(\"[ Acceptable ServersThreadPool ] \",\n                    2,\n                    10,\n                    new ArrayBlockingQueue<Runnable>(65500),\n                    Thread.NORM_PRIORITY - 2);\n            ssc = ServerSocketChannel.open();\n            ssc.configureBlocking(false);\n            ss = ssc.socket();\n            ss.bind(new InetSocketAddress(config.getPort()));\n            sel = Selector.open();\n            ssc.register(sel, SelectionKey.OP_ACCEPT);\n            System.out.println(\"READY\");\n            Utils.waitAndWork(executor, ss, sel, config);\n        } finally {\n            logger.log(Level.INFO, \"[FDT] [ waitForTask ] main loop FINISHED!\");\n            // close all the stuff\n            Utils.closeIgnoringExceptions(ssc);\n            Utils.closeIgnoringExceptions(sel);\n            Utils.closeIgnoringExceptions(ss);\n            if (executor != null) {\n                executor.shutdown();\n            }\n        }\n    }\n\n    private void initApMon() throws Exception {\n        final String configApMonHosts = config.getApMonHosts();\n        if (configApMonHosts != null) {\n            long lStart = System.currentTimeMillis();\n\n            ApMon apmon = null;\n\n            final String apMonHosts = (configApMonHosts.length() > 0) ? configApMonHosts : MONALISA2_CERN_CH;\n\n            logger.info(\"Trying to instantiate apMon to: \" + apMonHosts);\n            try {\n                Vector<String> vHosts = new Vector<>();\n                Vector<Integer> vPorts = new Vector<>();\n                final String[] apMonDstTks = apMonHosts.split(\",\");\n\n                if (apMonDstTks.length == 0) {\n                    logger.log(Level.WARNING, \"\\n\\nApMon enabled but no hosts defined! Cannot send apmon statistics\\n\\n\");\n                } else {\n                    for (String host_port : apMonDstTks) {\n                        int index;\n                        String host;\n                        int port;\n                        if ((index = host_port.indexOf(':')) != -1) {\n                            host = host_port.substring(0, index);\n                            try {\n                                port = Integer.parseInt(host_port.substring(index + 1));\n                            } catch (Exception ex) {\n                                port = 28884;\n                            }\n                        } else {\n                            host = host_port;\n                            port = 28884;\n                        }\n                        vHosts.add(host);\n                        vPorts.add(port);\n                    }\n\n                    ApMon.setLogLevel(\"WARNING\");\n                    apmon = new ApMon(vHosts, vPorts);\n                    apmon.setConfRecheck(false, -1);\n                    apmon.setGenMonitoring(true, 40);\n                    // apmon.setJobMonitoring(, )\n                    // apmon.setMaxMsgRate(50);\n                    String cluster_name;\n                    String node_name;\n                    if (config.getHostName() != null) {// client\n                        cluster_name = \"Clients\";\n                        node_name = config.getHostName();\n                    } else {// server\n                        cluster_name = \"Servers\";\n                        node_name = apmon.getMyHostname();\n                    }\n                    apmon.setMonitorClusterNode(cluster_name, node_name);\n                    // apmon.setRecheckInterval(-1)\n                    apmon.setSysMonitoring(true, 40);\n                    try {\n                        apmon.sendParameter(cluster_name, node_name, \"FDT_version\", FDT_FULL_VERSION);\n                    } catch (Exception e) {\n                        logger.info(\"Send operation failed: \");\n                        e.printStackTrace();\n                    }\n\n                }\n            } catch (Throwable ex) {\n                logger.log(Level.WARNING, \"Error initializing ApMon engine.\", ex);\n            } finally {\n                Utils.initApMonInstance(apmon);\n            }\n\n            try {\n                if (Utils.getApMon() != null) {\n                    ApMonReportingTask apmrt = new ApMonReportingTask();\n                    Utils.getMonitoringExecService().scheduleWithFixedDelay(apmrt, 1,\n                            config.getApMonReportingInterval(), TimeUnit.SECONDS);\n                } else {\n                    logger.log(Level.WARNING, \"Cannot start ApMonReportingTask because apMon is null!\");\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Cannot start ApMonReportingTask because got Exception.\", t);\n            }\n\n            long lEnd = System.currentTimeMillis();\n            logger.info(\"ApMon initialization took \" + (lEnd - lStart) + \" ms\");\n        }\n    }\n\n    /**\n     * Helper class for \"graceful\" shutdown of FDT.\n     */\n    private final static class GracefulStopper extends AbstractFDTCloseable {\n\n        private boolean internalClosed = false;\n\n        protected synchronized void internalClose() throws Exception {\n            this.internalClosed = true;\n            this.notifyAll();\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDT.manifest",
    "content": "Main-Class: lia.util.net.copy.FDTMain\nClass-Path: \n"
  },
  {
    "path": "src/lia/util/net/copy/FDTMain.java",
    "content": "/*\n * Created on Apr 29, 2011\n */\npackage lia.util.net.copy;\n\nimport java.lang.reflect.Method;\n\n/**\n * Just a wrapper to check for Java version.</br>\n * FDT main class is invoked using reflection\n *\n * @author ramiro\n * @since FDT 0.9.22\n */\npublic class FDTMain {\n\n    private final static String MIN_REQ_VERSION = \"1.6\";\n\n    /**\n     * @param args\n     * @throws Exception\n     */\n    public static void main(String[] args) throws Exception {\n        try {\n            final String specificationVersion = System.getProperty(\"java.specification.version\");\n            if (specificationVersion == null || specificationVersion.length() == 0) {\n                System.err.println(\"Unable to determine Java version '\" + specificationVersion + \"'\");\n                System.exit(-2);\n            }\n            final String trimVer = specificationVersion.trim();\n            final int cRez = MIN_REQ_VERSION.compareTo(trimVer);\n            if (cRez > 0) {\n                System.err.println(\"\\nYour current java version: \" + trimVer + \" is not supported.\");\n                System.err.println(\"Minimum required version: \" + MIN_REQ_VERSION);\n                System.err.println(\"\\nYou can download latest Java from http://java.com.\\n\");\n                System.err.println(\"local java.specification.version=\" + trimVer);\n                System.err.println(\"local java.version=\" + System.getProperty(\"java.version\"));\n                System.err.println(\"local java.runtime.version=\" + System.getProperty(\"java.runtime.version\"));\n                System.err.println(\"\");\n                System.exit(122);\n            }\n        } catch (Throwable t) {\n            System.err.println(\"Unable to determine Java version. Cause:\");\n            t.printStackTrace();\n            System.exit(-2);\n        }\n\n        // Reflection is the only way to go ...\n        try {\n            Class fdtMainClass = Class.forName(\"lia.util.net.copy.FDT\");\n            Class[] sClass = new Class[]{\n                    args.getClass()\n            };\n            Method mainMethod = fdtMainClass.getDeclaredMethod(\"main\", sClass);\n            mainMethod.invoke((Object) null, new Object[]{\n                    args\n            });\n        } catch (Throwable t) {\n            t.printStackTrace();\n            System.exit(22);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDTReaderSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.*;\nimport lia.util.net.copy.disk.DiskReaderManager;\nimport lia.util.net.copy.disk.DiskReaderTask;\nimport lia.util.net.copy.filters.Postprocessor;\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\nimport lia.util.net.copy.transport.*;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.net.InetAddress;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.*;\nimport java.util.Map.Entry;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The \"reader\" session; it will send data over the wire\n *\n * @author ramiro\n */\npublic class FDTReaderSession extends FDTSession implements FileBlockProducer {\n\n    public static final long END_RCV_WAIT_DELAY = TimeUnit.SECONDS.toNanos(120);\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(FDTReaderSession.class.getName());\n    private static final DiskReaderManager diskManager = DiskReaderManager.getInstance();\n    private static final Config config = Config.getInstance();\n    private static final int MAX_TAKE_POLL_ITER = Config.getMaxTakePollIter();\n    public final BlockingQueue<FileBlock> fileBlockQueue;\n    private final TreeMap<Integer, ArrayList<DiskReaderTask>> readersMap;\n    private final boolean isFileList;\n    private final AtomicBoolean finalCleaupExecuted = new AtomicBoolean(false);\n    private final AtomicBoolean finishNotifiedExecuted = new AtomicBoolean(false);\n    private volatile ExecutorService execService;\n    private String remoteDir;\n    private boolean recursive;\n    private int totalFileBlocks = 0;\n    private ProcessorInfo processorInfo;\n    private int readersCount = 1;\n\n    /**\n     * LOCAL SESSION - look in the Config\n     *\n     * @throws Exception\n     */\n    public FDTReaderSession(int transferPort) throws Exception {\n        super(FDTSession.CLIENT, transferPort);\n        Utils.initLogger(config.getLogLevel(), new File(System.getProperty(\"java.io.tmpdir\") + File.separatorChar + sessionID + \".log\"), new Properties());\n        final int rMul = Integer.getInteger(\"fdt.rQueueM\", 2);\n        final int avProcProp = Integer.getInteger(\"fdt.avProc\", 1);\n        final int avProcMax = Math.max(avProcProp, Utils.availableProcessors());\n        fileBlockQueue = new ArrayBlockingQueue<>(avProcMax * rMul);\n        readersMap = new TreeMap<>();\n        diskManager.addSession(this);\n        this.remoteDir = config.getDestinationDir();\n        this.recursive = config.isRecursive();\n        this.isFileList = (config.getConfigMap().get(\"-fl\") != null);\n        this.monID = config.getMonID();\n        readersCount = config.getReadersCount();\n\n        if (readersCount <= 0) {\n            readersCount = 1;\n        }\n\n        localInit();\n    }\n\n    /**\n     * REMOTE SESSION - wait for init()\n     *\n     * @param ctrlChannel\n     * @throws Exception\n     */\n    public FDTReaderSession(ControlChannel ctrlChannel) throws Exception {\n        super(ctrlChannel, FDTSession.SERVER);\n        Utils.initLogger(config.getLogLevel(), new File(System.getProperty(\"java.io.tmpdir\") + File.pathSeparatorChar + sessionID + \".log\"), new Properties());\n        fileBlockQueue = new ArrayBlockingQueue<FileBlock>(Utils.availableProcessors() * 2);\n        readersMap = new TreeMap<Integer, ArrayList<DiskReaderTask>>();\n\n        this.remoteDir = (String) ctrlChannel.remoteConf.get(\"-d\");\n        this.recursive = (ctrlChannel.remoteConf.get(\"-r\") != null);\n        this.isFileList = (ctrlChannel.remoteConf.get(\"-fl\") != null);\n\n        this.monID = (String) this.controlChannel.remoteConf.get(\"-monID\");\n\n        readersCount = config.getReadersCount();\n\n        if (readersCount <= 0) {\n            readersCount = 1;\n        }\n\n        String srReadersCount = (String) ctrlChannel.remoteConf.get(\"-rCount\");\n\n        int rReadersCount = readersCount;\n\n        if (srReadersCount != null) {\n            try {\n                rReadersCount = Integer.parseInt(srReadersCount);\n            } catch (Throwable t) {\n                rReadersCount = readersCount;\n            }\n        }\n\n        readersCount = rReadersCount;\n\n        diskManager.addSession(this);\n    }\n\n    private void localInit() throws Exception {\n\n        final String[] fileList = config.getFileList();\n        final String[] remappedFileList = config.getRemappedFileList();\n        this.recursive = config.isRecursive();\n\n        internalInit(fileList, remappedFileList);\n    }\n\n    private void internalInit(final String[] fileList, final String[] remappedFileList) throws Exception {\n        final boolean isFiner = logger.isLoggable(Level.FINER);\n        final boolean isFine = isFiner || logger.isLoggable(Level.FINE);\n\n        if (isFiner) {\n            logger.log(Level.FINER, \"\\n\\n FDTReaderSession - internalInit ENTER \\n\\n FileList:\\n\"\n                    + Arrays.toString(fileList) + \"\\n\\nRemappedFileList:\\n\" + Arrays.toString(remappedFileList));\n        }\n\n        int filtersCount = 0;\n        final ProcessorInfo info = new ProcessorInfo();\n        final long sTime = System.nanoTime();\n\n        try {\n            final String preProcessFiltersProp = config.getPreFilters();\n\n            if ((preProcessFiltersProp == null) || (preProcessFiltersProp.length() == 0)) {\n                if (isFine) {\n                    logger.log(Level.FINE, \"No FDT Preprocess Filters defined\");\n                }\n            } else {\n                String[] preProcessFilters = preProcessFiltersProp.split(\",\");\n                if ((preProcessFilters == null) || (preProcessFilters.length == 0)) {\n                    logger.log(Level.WARNING, \"Cannot understand -preFilters option!\");\n                } else {\n                    filtersCount = preProcessFilters.length;\n\n                    info.fileList = new String[fileList.length];\n                    info.destinationDir = (this.remoteDir == null) ? config.getDestinationDir()\n                            : this.remoteDir;\n                    info.remoteAddress = this.controlChannel.remoteAddress;\n                    info.remotePort = this.controlChannel.remotePort;\n                    info.recursive = this.recursive;\n\n                    System.arraycopy(fileList, 0, info.fileList, 0, fileList.length);\n\n                    for (final String filterName : preProcessFilters) {\n                        preProcess(info, filterName);\n                    }\n                }\n            }\n        } finally {\n            StringBuilder sb = new StringBuilder();\n            if (filtersCount > 0) {\n                sb.append(\"[ FDTReaderSession ] Preprocessing: \").append(filtersCount).append(\" filters in \")\n                        .append(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sTime)).append(\" ms\");\n            } else {\n                sb.append(\"[ FDTReaderSession ] No pre processing filters defined/processed.\");\n            }\n            logger.log(Level.INFO, sb.toString());\n        }\n\n        Map<String, String> initialMapping = new HashMap<String, String>();\n        List<String> newFileList = new ArrayList<String>();\n        Map<String, String> newRemappedFileList = new HashMap<String, String>();\n\n        if (filtersCount > 0) {\n            this.processorInfo = info;\n            this.remoteDir = info.destinationDir;\n            newFileList = new ArrayList<>(info.fileList.length);\n            newFileList.addAll(Arrays.asList(info.fileList));\n        } else {\n            if (recursive) {\n\n                final int len = fileList.length;\n                for (int iter = 0; iter < len; iter++) {\n                    final String fName = fileList[iter];\n                    final String remappedFName = (remappedFileList == null) ? null : remappedFileList[iter];\n                    // System.out.println(\" ==== START fName ==== \" + fName);\n                    List<String> tmpFL = new ArrayList<String>();\n                    List<String> tmpRFL = new ArrayList<String>();\n                    Utils.getRecursiveFiles(fName, remappedFName, tmpFL, tmpRFL);\n                    if (!isFileList) {\n                        for (String ffName : tmpFL) {\n                            String parent = initialMapping.get(ffName);\n                            if (parent != null) {\n                                if (fName.length() > parent.length()) {\n                                    parent = fName;\n                                }\n                            } else {\n                                parent = fName;\n                            }\n                            if (new File(parent).isDirectory()) {\n                                initialMapping.put(new File(ffName).getAbsolutePath(),\n                                        new File(parent).getAbsolutePath());\n                            }\n                        }\n                    }\n                    newFileList.addAll(tmpFL);\n                    int c = 0;\n                    for (String fname : tmpFL) {\n                        newRemappedFileList.put(new File(fname).getAbsolutePath(), tmpRFL.get(c++));\n                    }\n                }\n            } else {\n                newFileList = Arrays.asList(fileList);\n                int c = 0;\n                if (remappedFileList != null) {\n                    for (String f : newFileList) {\n                        if (new File(f).isFile()) {\n                            newRemappedFileList.put(new File(f).getAbsolutePath(), remappedFileList[c++]);\n                        }\n                    }\n                } else {\n                    newRemappedFileList = null;\n                }\n            }\n        }\n\n        final FileChannelProvider fcp = Config.getInstance().getFileChannelProviderFactory()\n                .newReaderFileChannelProvider(this);\n\n        for (final String fName : newFileList) {\n            if (!new File(fName).exists()) {\n                logger.warning(\"File listed in file list does not exist! \" + fName);\n                controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.FILE_NOT_FOUND, fName));\n                controlChannel.emptyMsgQueue();\n                throw new FileNotFoundException(\"File does not exist! \" + fName);\n            }\n                FileReaderSession frs = new FileReaderSession(fName, this, isLoop, fcp);\n                fileSessions.put(frs.sessionID, frs);\n                setSessionSize(sessionSize() + frs.sessionSize());\n\n        }\n\n        buildPartitionMap();\n        int size = partitionsMap.size();\n\n        if (size == 0) {\n            throw new FDTProcolException(\"\\n\\nERROR: Cannot identify partition map for the specified fileList: \"\n                    + Arrays.toString(fileList) + \" No such file or directory ??\");\n        }\n\n        if (isFiner) {\n            logger.log(Level.FINER,\n                    \"\\n\\n FDTReaderSession - internalInit FINISHED - sendingRemoteSessions \\n\\n initialMapping:\\n\"\n                            + initialMapping + \"\\n\\n newRemappedFileList:\\n\" + newRemappedFileList);\n        }\n\n        sendRemoteSessions(initialMapping, newRemappedFileList);\n    }\n\n    private void preProcess(ProcessorInfo processorInfo, String filterName) throws Exception {\n        boolean searchElsewhere = false;\n        Preprocessor preprocessor = null;\n        try {\n            preprocessor = (Preprocessor) (Class.forName(\"lia.util.net.copy.filters.examples.\" + filterName).newInstance());\n        } catch (ClassNotFoundException e) {\n            searchElsewhere = true;\n        }\n        if (searchElsewhere) {\n            try {\n                String userDirectory = System.getProperty(\"user.dir\");\n                File filter = new File(userDirectory + File.separator + \"plugins\" + File.separator);\n                logger.log(Level.FINER, \"Trying to load plugin from 'plugins' directory. \" + filter.toString());\n\n                URL url = filter.toURL();\n                URL[] urls = new URL[]{url};\n                ClassLoader cl = new URLClassLoader(urls);\n                Class cls = cl.loadClass(filterName);\n\n                preprocessor = (Preprocessor) cls.newInstance();\n            } catch (Exception e) {\n                logger.log(Level.FINER, \"Failed to load filter from external plugins directory. \" + e);\n                preprocessor = (Preprocessor) (Class.forName(filterName).newInstance());\n            }\n        }\n        if (preprocessor != null) {\n            preprocessor.preProcessFileList(processorInfo, this.controlChannel.subject);\n        }\n    }\n\n    @Override\n    public long getSize() {\n        return sessionSize();\n    }\n\n    private void sendRemoteSessions(final Map<String, String> initialMapping, Map<String, String> newRemappedFileList)\n            throws Exception {\n        FDTSessionConfigMsg sccm = new FDTSessionConfigMsg();\n\n        sccm.destinationDir = this.remoteDir;\n        sccm.recursive = recursive;\n\n        int count = fileSessions.size();\n\n        sccm.fileIDs = new UUID[count];\n        sccm.fileLists = new String[count];\n        sccm.remappedFileLists = new String[count];\n        sccm.fileSizes = new long[count];\n        sccm.lastModifTimes = new long[count];\n\n        count = 0;\n        for (Map.Entry<UUID, FileSession> entry : fileSessions.entrySet()) {\n\n            FileSession fs = entry.getValue();\n\n            sccm.fileIDs[count] = fs.sessionID;\n\n            if (isFileList) {\n                sccm.fileLists[count] = fs.fileName;\n                sccm.remappedFileLists[count] = (newRemappedFileList == null) ? null\n                        : newRemappedFileList.get(fs.fileName);\n            } else if (initialMapping.size() == 0) {\n                sccm.fileLists[count] = fs.getFile().getName();\n            } else {\n                String parent = initialMapping.get(fs.fileName);\n                String name = fs.fileName;\n\n                if ((parent != null) && (parent.length() < name.length())) {\n                    name = name.substring(parent.length() - new File(parent).getName().length());\n                }\n\n                if (parent == null) {\n                    name = fs.getFile().getName();\n                }\n\n                sccm.fileLists[count] = name;\n            }\n            sccm.fileSizes[count] = fs.sessionSize;\n            sccm.lastModifTimes[count] = fs.lastModified;\n\n            count++;\n        }\n\n        controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.FINAL_FDTSESSION_CONF, sccm));\n\n        setCurrentState(FINAL_CONF_SENT);\n    }\n\n    public void setControlChannel(ControlChannel controlChannel) {\n        this.controlChannel = controlChannel;\n    }\n\n    public boolean finishReader(int partitionID, DiskReaderTask drt) {\n\n        boolean bRet = true;\n\n        synchronized (readersMap) {\n            final ArrayList<DiskReaderTask> readersList = readersMap.get(partitionID);\n            if (readersList != null) {\n                if (!readersList.remove(drt)) {\n                    bRet = false;\n                    logger.log(Level.WARNING, \" The DiskReaderTask \");\n                }\n            }\n        }\n\n        return bRet;\n    }\n\n    /**\n     * @param partitionID\n     */\n    public void notifyReaderDown(int partitionID) {\n        // TODO - not yet used\n    }\n\n    @Override\n    public void finishFileSession(UUID sessionID, Throwable dCause) {\n        super.finishFileSession(sessionID, dCause);\n        if (finishedSessions.size() == fileSessions.size()) {\n            notifySessionFinished();\n        }\n    }\n\n    public void startReading() {\n\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(\" Started DiskReaderTasks for the following partions [ \");\n        int idx = 0;\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \" partitionsMap is: \" + partitionsMap);\n        }\n\n        for (Entry<Integer, LinkedList<FileSession>> entry : partitionsMap.entrySet()) {\n            final int partitionID = entry.getKey().intValue();\n\n            LinkedList<FileSession> files = entry.getValue();\n\n            int realReadersCount = (readersCount < files.size()) ? readersCount : files.size();\n            ArrayList<DiskReaderTask> readersTasks = new ArrayList<DiskReaderTask>(realReadersCount);\n\n            ArrayList<LinkedList<FileSession>> fileSessionsReaders = new ArrayList<LinkedList<FileSession>>(\n                    realReadersCount);\n\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \" realReadersCount = \" + realReadersCount + \" for partitionID: \" + partitionID);\n            }\n\n            if (realReadersCount > 1) {\n                FileSession[] filesArray = files.toArray(new FileSession[files.size()]);\n                Arrays.sort(filesArray, new FileSessionComparator());\n\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Sorted FileSession-s array: \" + Arrays.toString(filesArray));\n                }\n\n                int ci = 0;\n                for (FileSession fs : filesArray) {\n                    LinkedList<FileSession> fsessions = (ci >= fileSessionsReaders.size()) ? null\n                            : fileSessionsReaders.get(ci);\n\n                    if (fsessions == null) {\n                        fsessions = new LinkedList<FileSession>();\n                        fileSessionsReaders.add(fsessions);\n                    }\n\n                    fsessions.add(fs);\n\n                    if (logger.isLoggable(Level.FINEST)) {\n                        logger.log(Level.FINEST, \" Added FileSession: \" + fs + \" for DiskReaderTask idx =  \" + ci);\n                    }\n                    ci = (ci + 1) % realReadersCount;\n                }\n\n            } else {\n                fileSessionsReaders.add(files);\n            }\n\n            execService = Utils.getStandardExecService(\"DiskReaderTask for \" + toString(), partitionsMap.size(),\n                    (partitionsMap.size() * realReadersCount) + 5, Thread.NORM_PRIORITY);\n\n            for (int i = 0; i < realReadersCount; i++) {\n                final DiskReaderTask drTask = new DiskReaderTask(partitionID, idx++, fileSessionsReaders.get(i), this);\n                readersTasks.add(drTask);\n                execService.submit(drTask);\n            }\n\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \" ReadersTasks for partitionID: \" + partitionID + \": \" + readersTasks);\n            }\n\n            readersMap.put(partitionID, readersTasks);\n            sb.append(partitionID).append(\" \");\n        }\n\n        sb.append(\"] for FDTSession: \").append(sessionID);\n\n        logger.log(Level.INFO, sb.toString());\n\n    }\n\n    private boolean doPostProcessing() throws Exception {\n\n        if (!postProcessingDone.compareAndSet(false, true)) {\n            return false;\n        }\n\n        final long sTime = System.nanoTime();\n        int filtersCount = 0;\n\n        try {\n            logger.log(Level.INFO, \"[ FDTReaderSession ] Post Processing started\");\n            final String postProcessFiltersProp = config.getPostFilters();\n\n            if ((postProcessFiltersProp == null) || (postProcessFiltersProp.length() == 0)) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \" [ FDTReaderSession ] No FDT PostProcessor Filters defined\");\n                }\n            } else {\n                final String[] postProcessFilters = postProcessFiltersProp.split(\",\");\n                if ((postProcessFilters == null) || (postProcessFilters.length == 0)) {\n                    logger.log(Level.WARNING, \"Cannot understand -postFilters\");\n                } else {\n                    filtersCount = postProcessFilters.length;\n\n                    for (final String filterName : postProcessFilters) {\n                        Postprocessor preprocessor = (Postprocessor) (Class.forName(filterName).newInstance());\n                        preprocessor.postProcessFileList(this.processorInfo, this.controlChannel.subject, downCause(),\n                                downMessage());\n                    }\n\n                }\n            }\n        } finally {\n            StringBuffer sb = new StringBuffer();\n            if (filtersCount > 0) {\n                sb.append(\"[ FDTReaderSession ] Postprocessing: \").append(filtersCount).append(\" filters in \")\n                        .append(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sTime)).append(\" ms\");\n            } else {\n                sb.append(\"[ FDTReaderSession ] No post processing filters defined/processed.\");\n            }\n            logger.log(Level.INFO, sb.toString());\n        }\n\n        return (filtersCount > 0);\n    }\n\n    private void notifySessionFinished() {\n\n        if (finishNotifiedExecuted.compareAndSet(false, true)) {\n            StringBuilder downNotif = null;\n\n            try {\n                if ((downMessage() != null) && (downCause() != null)) {\n\n                    downNotif = new StringBuilder();\n\n                    if (downMessage() != null) {\n                        downNotif.append(\"Down message: \").append(downMessage()).append(\"\\n\");\n                    }\n\n                    if (downCause() != null) {\n                        downNotif.append(\"Down cause:\\n\").append(Utils.getStackTrace(downCause())).append(\"\\n\");\n                    }\n                }\n            } catch (Throwable t1) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE,\n                            \"[ FDTReaderSession ] [ notifySessionFinished ]  Got exception building the remote notify message\",\n                            t1);\n                }\n            }\n\n            try {\n                controlChannel.sendCtrlMessage(\n                        new CtrlMsg(CtrlMsg.END_SESSION, (downNotif == null) ? md5Sums : downNotif.toString()));\n            } catch (Throwable t1) {\n                logger.log(Level.WARNING,\n                        \" [ FDTReaderSession ] [ notifySessionFinished ] got exception sending END_SESSION message\",\n                        t1);\n            }\n        }\n    }\n\n    private void finalCleanup() {\n        if (finalCleaupExecuted.compareAndSet(false, true)) {\n            final boolean isFiner = logger.isLoggable(Level.FINER);\n            final boolean isFine = isFiner || logger.isLoggable(Level.FINE);\n\n            try {\n                final long sTime = System.nanoTime();\n                while ((currentState() & END_RCV) != END_RCV) {\n                    try {\n                        Thread.sleep(1000);\n                        notifySessionFinished();\n                    } catch (InterruptedException ie) {\n                        Thread.interrupted();\n                    } catch (Throwable t) {\n                        if (isFine) {\n                            logger.log(Level.FINE, \"[finalCleanup] exception notifying sessionFinished. Cause\", t);\n                        }\n                    }\n\n                    if (controlChannel.isSocketClosed()) {\n                        break;\n                    }\n\n                    if ((System.nanoTime() - sTime) > END_RCV_WAIT_DELAY) {\n                        logger.log(Level.WARNING,\n                                \" Remote FDT Writer session went down since we finished reading. The session will finish\");\n                        break;\n                    }\n                }\n            } catch (Throwable t) {\n                if (isFine) {\n                    logger.log(Level.FINE, \"[finalCleanup] exception notifying sessionFinished. Cause\", t);\n                }\n            }\n\n            if (isFiner) {\n                logger.log(Level.FINER, \"\\n\\n\\n [ FDTReaderSession ]  [ finalCleanup ]   EXECUTING !!!!!!!!!!! \\n\\n\");\n            }\n\n            // for logging the time the transfer completed\n            final Date endDate = new Date();\n\n            NetloggerRecord nlrec = new NetloggerRecord();\n            nlrec.setBlock(DirectByteBufferPool.getInstance().getBufferSize());\n            nlrec.setBuffer(Math.max(0, config.getSockBufSize()));\n            if (downCause() == null && downMessage() == null) {\n                nlrec.setCode(\"226\");  // = \"Closing data connection. Requested file action successful.\"\n            } else {\n                nlrec.setCode(\"426\");  // = \"Connection closed; transfer aborted.\"\n            }\n            nlrec.setCompleted(endDate);\n            nlrec.setDestination(controlChannel.remoteAddress);\n            try {\n                nlrec.setHost(InetAddress.getLocalHost());\n            } catch (java.net.UnknownHostException ex) {\n                /* do nothing */\n            }\n            nlrec.setNbytes(getTotalBytes());\n            nlrec.setStart(new Date(startTimeMillis));\n            if (getTransportProvider() != null) {\n                nlrec.setStreams(getTransportProvider().getNumberOfStreams());\n            }\n            nlrec.setType(\"RETR\");\n\n            logger.info(nlrec.toULMString());\n\n            // log final statistics\n            try {\n                StringBuilder sb = new StringBuilder();\n                sb.append(\"\\n\\nFDTReaderSession ( \").append(sessionID);\n                if (monID != null) {\n                    sb.append(\" / \").append(monID);\n                }\n                sb.append(\" ) final stats:\");\n                sb.append(\"\\n Started: \").append(new Date(startTimeMillis));\n                sb.append(\"\\n Ended:   \").append(endDate);\n                long period = System.nanoTime() - startTimeNanos;\n                sb.append(\"\\n Transfer period:   \")\n                        .append(Utils.getETA(TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTimeNanos)));\n                sb.append(\"\\n TotalBytes: \").append(getTotalBytes());\n                if (transportProvider != null) {\n                    sb.append(\"\\n TotalNetworkBytes: \").append(transportProvider.getUtilBytes());\n                    try {\n                        if (!Utils.updateTotalReadCounter(transportProvider.getUtilBytes())) {\n                            if (logger.isLoggable(Level.FINEST)) {\n                                logger.log(Level.FINEST,\n                                        \" [ FDTReaderSession ] Unable to update the contor in the update file.\");\n                            }\n                        }\n                    } catch (Throwable tu) {\n                        if (logger.isLoggable(Level.FINEST)) {\n                            logger.log(Level.FINEST,\n                                    \" [ FDTReaderSession ] Unable to update the contor in the update file. Cause: \",\n                                    tu);\n                        }\n                    } finally {\n                        transportProvider.close(downMessage(), downCause());\n                    }\n                } else {\n                    sb.append(\"\\n TotalNetworkBytes: 0\");\n                }\n                sb.append(\"\\n Exit Status: \")\n                        .append(((downCause() == null) && (downMessage() == null)) ? \"OK\" : \"Not OK\");\n                sb.append(\"\\n\");\n                logger.info(sb.toString());\n                System.out.println(sb.toString());\n                if (config.getMonitor().equals(Config.OPENTSDB)) {\n                    MonitoringUtils monUtils = new MonitoringUtils(config, this);\n                    monUtils.monitorEndStats(((downCause() == null) && (downMessage() == null)),getTotalBytes(), transportProvider.getUtilBytes(),\n                            startTimeMillis,  endDate.getTime(), period, \"Readers\");\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING,\n                        \"[ FDTReaderSession ] [ finalCleanup ] [ HANDLED ] Exception getting final statistics. Smth went dreadfully wrong!\",\n                        t);\n            }\n\n            try {\n                for (final FileSession fileSession : fileSessions.values()) {\n                    try {\n                        fileSession.close(downMessage(), downCause());\n                    } catch (Throwable ign) {\n                        if (isFiner) {\n                            logger.log(Level.FINER, \"finalCleanup - exception closing file. Cause: \", ign);\n                        }\n                    }\n                }\n            } catch (Throwable ignore) {\n                if (isFiner) {\n                    logger.log(Level.FINER, \"finalCleanup - exception closing files. Cause: \", ignore);\n                }\n            }\n\n            try {\n                doPostProcessing();\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"\\n [ FDTReaderSession ] Got exception in postProcessing\", t);\n            }\n\n            try {\n                final ControlChannel controlChannel = this.controlChannel;\n                if (controlChannel != null) {\n                    controlChannel.close(downMessage(), downCause());\n                }\n            } catch (Throwable ignore) {\n                if (isFiner) {\n                    logger.log(Level.FINER, \"finalCleanup - exception closing control channel. Cause: \", ignore);\n                }\n            }\n\n            final ExecutorService execService = this.execService;\n            if (execService != null) {\n                try {\n                    execService.shutdown();\n                    execService.awaitTermination(10, TimeUnit.SECONDS);\n                } catch (Throwable ignore) {\n                    if (isFiner) {\n                        logger.log(Level.FINER, \"finalCleanup - exception closing executor service. Cause: \", ignore);\n                    }\n                } finally {\n                    execService.shutdownNow();\n                }\n            }\n\n            try {\n                diskManager.removeSession(this, downMessage(), downCause());\n            } catch (Throwable ignore) {\n                if (isFiner) {\n                    logger.log(Level.FINER, \"finalCleanup - exception removing session from diskManager. Cause: \",\n                            ignore);\n                }\n            }\n\n            try {\n                final int retBufs = Utils.drainFileBlockQueue(fileBlockQueue);\n                if (isFiner) {\n                    logger.log(Level.FINER, \"finalCleanup - recovered \" + retBufs + \" buffers\");\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING,\n                        \"\\n\\n [ FDTReaderSession ] [ HANDLED ] exception returning buffers to pool \\n\\n \", t);\n            }\n\n            try {\n                FDTSessionManager.getInstance().finishSession(sessionID, downMessage(), downCause());\n            } catch (Throwable ignore) {\n                if (isFiner) {\n                    logger.log(Level.FINER, \"finalCleanup - exception closing session in FDTSessionManager. Cause: \",\n                            ignore);\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void internalClose() throws Exception {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \" [ FDTReaderSession ] enters internalClose downMsg: \" + downMessage()\n                    + \" ,  downCause: \" + downCause());\n        }\n        try {\n            super.internalClose();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ FDTReaderSession ] [ HANDLED ] internalClose exception in base class.\", t);\n        }\n\n        final String downMessage = downMessage();\n        final Throwable downCause = downCause();\n\n        if ((downMessage != null) || (downCause != null)) {\n            final String downLogMsg = (downMessage == null) ? \"N/A\" : downMessage;\n            logger.log(Level.INFO, \"\\nThe FDTReaderSession ( \" + sessionID + \" ) finished with error(s). downMsg: \"\n                    + downLogMsg + \" downCause:\", downCause());\n            try {\n                finalCleanup();\n            } catch (Throwable t) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"[internalClose] Exception in finalCleanup. Cause: \", t);\n                }\n            }\n        } else {\n            Runnable r = new Runnable() {\n\n                @Override\n                public void run() {\n                    finalCleanup();\n                }\n            };\n\n            Utils.getMonitoringExecService().schedule(r, 3, TimeUnit.SECONDS);\n        }\n    }\n\n    @Override\n    public void handleInitFDTSessionConf(CtrlMsg ctrlMsg) throws Exception {\n\n        FDTSessionConfigMsg sccm = (FDTSessionConfigMsg) ctrlMsg.message;\n\n        this.remoteDir = sccm.destinationDir;\n        this.recursive = sccm.recursive;\n\n        internalInit(sccm.fileLists, sccm.remappedFileLists);\n    }\n\n    @Override\n    public void handleFinalFDTSessionConf(CtrlMsg ctrlMsg) throws Exception {\n        if (!(ctrlMsg.message instanceof UUID[])) {\n            FDTProcolException fpe = new FDTProcolException(\n                    \"Illegal message FINAL_FDT_CONF in ReaderSesssion without UUID[] as atttach. \" + ctrlMsg.message);\n            fpe.fillInStackTrace();\n            throw fpe;\n        }\n\n        UUID[] finishedSessions = (UUID[]) (ctrlMsg.message);\n        for (UUID fSession : finishedSessions) {\n            final FileSession fs = fileSessions.get(fSession);\n            if (fs != null) {\n                addAndGetUtilBytes(fs.sessionSize);\n                addAndGetTotalBytes(fs.sessionSize);\n            } else {\n                logger.log(Level.WARNING, \" No such UUID: \" + fSession\n                        + \" received from remote FDTWriterSession in local fileSessions list\");\n            }\n            finishFileSession(fSession, null);\n        }\n\n    }\n\n    @Override\n    public void handleEndFDTSession(CtrlMsg ctrlMsg) throws Exception {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER,\n                    \"\\n\\n\\n\\n\\n\\n ---------------- [ FDTReaderSession ] handleEndFDTSession. Msg: \" + ctrlMsg.message);\n        }\n\n        String remoteDownMsg = null;\n        try {\n            // SO I can close now ... wherever the status was before\n            if ((ctrlMsg.message != null) && (ctrlMsg.message instanceof String)) {\n                remoteDownMsg = (String) ctrlMsg.message;\n                close(remoteDownMsg, null);\n                logger.log(Level.WARNING, \"\\n\\n [ FDTReaderSession ] Remote FDTWriterSession for session [ \" + sessionID\n                        + \" ] finished with errors:\\n\" + remoteDownMsg + \"\\n\");\n            } else {\n                // everything went fine :)\n                logger.log(Level.INFO,\n                        \"[ FDTReaderSession ] Remote FDTWriterSession for session [ \" + sessionID + \" ] finished OK!\");\n                close(null, null);\n            }\n        } finally {\n            close((remoteDownMsg != null) ? remoteDownMsg : downMessage(), downCause());\n        }\n    }\n\n    /**\n     * @param ctrlMsg\n     */\n    @Override\n    public void handleStartFDTSession(CtrlMsg ctrlMsg) throws Exception {\n        // I will start the TransportProvider ... if every thing works as\n        // expected I will start sending\n        if (ctrlMsg.tag == CtrlMsg.REMOTE_TRANSFER_PORT) {\n            transferPort = (int) ctrlMsg.message;\n        }\n\n        boolean sendCookie = true;\n        if (role == CLIENT) {\n            sendCookie = false;\n            transportProvider = new TCPSessionWriter(this, InetAddress.getByName(config.getHostName()),\n                    transferPort, config.getSockNum());\n        } else {\n            transportProvider = new TCPSessionWriter(this);\n        }\n        config.registerTransferPortForSession(transferPort, sessionID.toString());\n        controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.START_SESSION, transferPort));\n        // I'm still in sync ... if smth goes wrong the state will not be set\n        setCurrentState(START_SENT);\n\n        if (config.getMonitor().equals(Config.OPENTSDB)) {\n            MonitoringUtils monUtils = new MonitoringUtils(config, this);\n            monUtils.monitorStart(System.currentTimeMillis(), \"Readers\");\n        }\n\n        startReading();\n\n        setCurrentState(TRANSFERING);\n        transportProvider.startTransport(sendCookie);\n    }\n\n    @Override\n    public void transportWorkerDown() throws Exception {\n        // fileBlockQueue.offer(FileBlock.EOF_FB);\n        close(\"wroker down\", null);\n    }\n\n    @Override\n    public FileBlock take() throws InterruptedException {\n\n        FileBlock fb = null;\n        // try a spinning poll(), avoid signaling\n        for (int i = 0; i < MAX_TAKE_POLL_ITER; i++) {\n            fb = fileBlockQueue.poll();\n            if (fb != null) {\n                return fb;\n            }\n        }\n\n        fb = fileBlockQueue.take();\n        if (fb != null) {\n            totalFileBlocks++;\n        }\n        return fb;\n    }\n\n    @Override\n    public FileBlock poll() {\n        final FileBlock fb = fileBlockQueue.poll();\n        if (fb != null) {\n            totalFileBlocks++;\n        }\n        return fb;\n    }\n\n    @Override\n    public FileBlock poll(long delay, TimeUnit unit) throws InterruptedException {\n        FileBlock fb = null;\n        fb = fileBlockQueue.poll(delay, unit);\n\n        if (fb != null) {\n            totalFileBlocks++;\n        }\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST,\n                    \" Polling for FileBlock qSize: \" + fileBlockQueue.size() + \" processedFBS: \" + totalFileBlocks);\n        }\n\n        return fb;\n    }\n\n    private static class FileSessionComparator implements Comparator<FileSession> {\n\n        @Override\n        public int compare(FileSession fileSession1, FileSession fileSession2) {\n            logger.log(Level.FINEST, \"[ FileSessionComparator ] Comparing \" + fileSession1.fileName + \" and \" + fileSession2.fileName);\n            if (fileSession1.fileName.equals(fileSession2.fileName)) {\n                if (fileSession1.sessionSize < fileSession2.sessionSize) {\n                    logger.log(Level.FINEST, \"[ FileSessionComparator ] Comparing session  size \" + fileSession1.sessionSize + \" and \" + fileSession2.sessionSize);\n                    return -1;\n                }\n                else if (fileSession1.file.length() < fileSession2.file.length())\n                {\n                    logger.log(Level.FINEST, \"[ FileSessionComparator ] Comparing file size \" + fileSession1.file.length() + \" and \" + fileSession2.file.length());\n                    return -1;\n                }\n            }\n\n            logger.log(Level.FINEST, \"[ FileSessionComparator ] Return 1\");\n            return 1;\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDTServer.java",
    "content": "package lia.util.net.copy;\n\nimport lia.gsi.FDTGSIServer;\nimport lia.util.net.common.*;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.UUID;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The accept() task will run in it's own thread ( including here the server )\n *\n * @author ramiro\n */\npublic class FDTServer extends AbstractFDTCloseable {\n\n    private static final Logger logger = Logger.getLogger(FDTServer.class.getName());\n\n    private static final Config config = Config.getInstance();\n\n    private static final FDTSessionManager fdtSessionManager = FDTSessionManager.getInstance();\n\n    final ServerSocketChannel ssc;\n\n    final ServerSocket ss;\n\n    final Selector sel;\n\n    //used by the AcceptableTask-s\n    final ExecutorService executor;\n\n    //signals the server stop\n    final AtomicBoolean hasToRun;\n\n    UUID fdtSessionID;\n\n    public FDTServer(int port) throws Exception {\n        hasToRun = new AtomicBoolean(true);\n\n        // We are not very happy to welcome new clients ... so the priority will be lower\n        executor = Utils.getStandardExecService(\"[ Acceptable ServersThreadPool ] \",\n                5,\n                10,\n                new ArrayBlockingQueue<Runnable>(65500),\n                Thread.NORM_PRIORITY - 2);\n        ssc = ServerSocketChannel.open();\n        ssc.configureBlocking(false);\n\n        ss = ssc.socket();\n\n        String listenIP = config.getListenAddress();\n        if (listenIP == null) {\n            ss.bind(new InetSocketAddress(port));\n        }\n        else\n        {\n            ss.bind(new InetSocketAddress(InetAddress.getByName(listenIP), port));\n        }\n\n        sel = Selector.open();\n        ssc.register(sel, SelectionKey.OP_ACCEPT);\n\n        if (config.isGSIModeEnabled()) {\n            FDTGSIServer gsiServer = new FDTGSIServer(config.getGSIPort());\n            gsiServer.start();\n            logger.log(Level.INFO, \"FDT started in GSI mode on port: \" + config.getGSIPort());\n        }\n        // Monitoring & Nice Prnting\n        final ScheduledExecutorService monitoringService = Utils.getMonitoringExecService();\n\n        monitoringService.scheduleWithFixedDelay(new FDTServerMonitorTask(), 10, 10, TimeUnit.SECONDS);\n\n        // in SSH mode this is a ACK message for the client to inform it that the server started ok\n        // (the server stdout is piped to client through the SSH channel)\n        System.out.println(\"READY\");\n    }\n\n    public static final boolean filterSourceAddress(java.net.Socket socket) {\n        /**\n         * check if remote client is allowed (based on optional filter specified in command line) if the address does\n         * not match, reject this IP (i.e DO NOT accept the session-tag\n         * from this client)\n         */\n        final NetMatcher filter = config.getSourceAddressFilter();\n        if (filter != null) {\n            logger.info(\"Enforcing source address filter: \" + filter);\n            final String sourceIPAddress = socket.getInetAddress().getHostAddress();\n            if (!filter.matchInetNetwork(sourceIPAddress)) {\n                Utils.closeIgnoringExceptions(socket);\n                logger.warning(\" Client [\" + sourceIPAddress + \"] is not allowed to transfer. Socket closed!\");\n                return false;\n            }\n        }\n        return true;\n\n    }\n\n    public static final void main(String[] args) throws Exception {\n        FDTServer jncs = new FDTServer(config.getPort());\n        jncs.doWork();\n    }\n\n    /**\n     * Safe to call multiple times; will return false if the server was already signaled to stop\n     * </br>\n     * <p>\n     * <b>Note:</b> Invoking this method acts as a signal for the server. Any ongoing transfers will continue until they finish\n     * </p>\n     *\n     * @return true if server was signaled to stop\n     */\n    public boolean stopServer() {\n        return hasToRun.compareAndSet(true, false);\n    }\n\n    public UUID getFdtSessionID() {\n        return fdtSessionID;\n    }\n\n    public void doWork() throws Exception {\n\n        Thread.currentThread().setName(\" FDTServer - Main loop worker \");\n        logger.info(\"FDTServer start listening on port: \" + ss.getLocalPort());\n\n        final boolean isStandAlone = config.isStandAlone();\n        try {\n            for (; ; ) {\n                if (!isStandAlone) {\n                    if (fdtSessionManager.isInited() && fdtSessionManager.sessionsNumber() == 0) {\n                        logger.log(Level.INFO, \"FDTServer will finish. No more sessions to serve.\");\n                        return;\n                    }\n                } else {\n                    if (!hasToRun.get()) {\n                        // stopServer was called\n                        if (fdtSessionManager.isInited() && fdtSessionManager.sessionsNumber() == 0) {\n                            logger.log(Level.INFO, \"FDTServer will finish. No more sessions to serve.\");\n                            return;\n                        }\n                    }\n                }\n                final int count = sel.select(2000);\n\n                if (count == 0)\n                    continue;\n\n                Iterator<SelectionKey> it = sel.selectedKeys().iterator();\n                while (it.hasNext()) {\n                    final SelectionKey sk = it.next();\n                    it.remove();\n\n                    if (!sk.isValid())\n                        continue;// closed socket ?\n\n                    if (sk.isAcceptable()) {\n                        final ServerSocketChannel ssc = (ServerSocketChannel) sk.channel();\n                        final SocketChannel sc = ssc.accept();\n\n                        try {\n                            executor.execute(new AcceptableTask(sc));\n                        } catch (Throwable t) {\n                            StringBuilder sb = new StringBuilder();\n                            sb.append(\"[ FDTServer ] got exception in while sumbiting the AcceptableTask for SocketChannel: \").append(sc);\n                            if (sc != null) {\n                                sb.append(\" Socket: \").append(sc.socket());\n                            }\n                            sb.append(\" Cause: \");\n                            logger.log(Level.WARNING, sb.toString(), t);\n                        }\n                    }\n                }\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"[FDTServer] Exception in main loop!\", t);\n            throw new Exception(t);\n        } finally {\n            logger.log(Level.INFO, \"[FDTServer] main loop FINISHED!\");\n            // close all the stuff\n            Utils.closeIgnoringExceptions(ssc);\n            Utils.closeIgnoringExceptions(sel);\n            Utils.closeIgnoringExceptions(ss);\n            if (executor != null) {\n                executor.shutdown();\n            }\n        }\n    }\n\n    public void run() {\n\n        try {\n            doWork();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"[ FDTServer ] exception main loop\", t);\n            close(\"[ FDTServer ] exception main loop\", t);\n        }\n\n        close(null, null);\n\n        logger.info(\" \\n\\n FDTServer finishes @ \" + new Date().toString() + \"!\\n\\n\");\n    }\n\n    @Override\n    protected void internalClose() {\n        // TODO Auto-generated method stub\n\n    }\n\n    static final class FDTServerMonitorTask implements Runnable {\n\n        public void run() {\n            // TODO Later\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDTSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.MonitoringUtils;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.monitoring.FDTSessionMonitoringTask;\nimport lia.util.net.copy.monitoring.lisa.LisaCtrlNotifier;\nimport lia.util.net.copy.transport.*;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.nio.file.Files;\nimport java.nio.file.LinkOption;\nimport java.nio.file.attribute.PosixFileAttributes;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Base class for both FDT Reader/Writer sessions\n *\n * @author ramiro\n */\npublic abstract class FDTSession extends IOSession implements ControlChannelNotifier, Comparable<FDTSession>,\n        Accountable, LisaCtrlNotifier {\n\n    public static final short SERVER = 0;\n    public static final short CLIENT = 1;\n    public static final short COORDINATOR = 2;\n    public static final int UNINITIALIZED = 0; // I think only OOM can do this\n    public static final int STARTED = 1 << 0;\n    public static final int INIT_CONF_SENT = 1 << 1;\n    public static final int INIT_CONF_RCV = 1 << 2;\n    public static final int FINAL_CONF_SENT = 1 << 3;\n    public static final int FINAL_CONF_RCV = 1 << 4;\n    public static final int START_SENT = 1 << 5;\n    public static final int START_RCV = 1 << 6;\n    public static final int TRANSFERING = 1 << 7;\n    public static final int END_SENT = 1 << 8;\n    public static final int END_RCV = 1 << 8;\n    public static final int COORDINATOR_MSG_RCVD = 1 << 9;\n    public static final int LIST_FILES_MSG_RCVD = 1 << 10;\n    public static final int MISSING_FILE = 1 << 11;\n    protected static final String[] FDT_SESION_STATES = {\"UNINITIALIZED\", \"STARTED\", \"INIT_CONF_SENT\",\n            \"INIT_CONF_RCV\", \"FINAL_CONF_SENT\", \"FINAL_CONF_RCV\", \"START_SENT\", \"START_RCV\", \"TRANSFERING\", \"END_SENT\",\n            \"END_RCV\"};\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(FDTSession.class.getName());\n    private static final String LISA_RATE_LIMIT_CMD = \"limit\";\n    private static final Config config = Config.getInstance();\n    /**\n     * can be either SERVER, either CLIENT\n     */\n    protected final short role; // for the moment could be boolean ... but never know for future extensions, e.g third\n    protected final Object protocolLock = new Object();\n    //to keep the order in which they were added use a LinkedHashMap\n    protected final Map<UUID, FileSession> fileSessions = new LinkedHashMap<UUID, FileSession>();\n    //to keep the order in which they were added use a LinkedHashMap\n    protected final Map<UUID, byte[]> md5Sums = new LinkedHashMap<UUID, byte[]>();\n    protected final boolean isNetTest;\n    protected final Object ctrlNotifLock = new Object();\n    protected final boolean customLog;\n    final FDTSessionMonitoringTask monitoringTask;\n    final ScheduledFuture<?> monitoringTaskFuture;\n    private final Object lock = new Object();\n    protected AtomicLong totalProcessedBytes;\n    protected AtomicLong totalUtilBytes;\n\n    // party transfers!\n    protected String monID;\n    // should be 0 in case everything works fine and !=0 in case of an error\n    protected short currentStatus;\n    protected ServerSocketChannel ssc;\n    protected ServerSocket ss;\n    protected Selector sel;\n    protected SocketChannel sc;\n    protected Socket s;\n    protected Map<Integer, LinkedList<FileSession>> partitionsMap;\n    protected ControlChannel controlChannel;\n    protected Set<UUID> finishedSessions = new TreeSet<UUID>();\n    protected TCPTransportProvider transportProvider;\n    protected AtomicBoolean postProcessingDone = new AtomicBoolean(false);\n    // use fixed block size for network I/O ?\n    protected boolean useFixedBlockSize = config.useFixedBlocks();\n    // do not try to write on the writer peer\n    protected boolean localLoop = config.localLoop();\n    protected int transferPort;\n    // is loop ?\n    protected boolean isLoop = config.loop();\n    protected String writeMode = config.getWriteMode();\n    // rateLimit ?\n    protected AtomicLong rateLimit = new AtomicLong(-1);\n    protected AtomicLong rateLimitDelay = new AtomicLong(300L);\n    ExecutorService executor;\n    // control thread started\n    AtomicBoolean ctrlThreadStarted = new AtomicBoolean(false);\n    // keeps the history of the states\n    private volatile int historyState;\n    // current state of the session\n    private volatile int currentState;\n\n    public FDTSession(short role, int transferPort) throws Exception {\n        super();\n        this.transferPort = transferPort;\n\n        customLog = Utils.isCustomLog();\n\n        currentStatus = 0;\n        this.totalProcessedBytes = new AtomicLong(0);\n        this.totalUtilBytes = new AtomicLong(0);\n\n        setCurrentState(STARTED);\n        this.role = role;\n        if (this.role == CLIENT || this.role == COORDINATOR) {\n            this.controlChannel = new ControlChannel(config.getHostName(), transferPort, sessionID(), this);\n        }\n        syncFDTConfig(controlChannel.remoteConf);\n        rateLimit.set(config.getRateLimit());\n        final long remoteRateLimit = Utils.getLongValue(controlChannel.remoteConf, \"-limit\", -1);\n        rateLimitDelay.set(config.getRateLimitDelay());\n        setNewRateLimit(remoteRateLimit, false);\n\n        if (rateLimit.get() > 0) {\n            logger.log(Level.INFO, \"Adding rate limit \" + rateLimit + \" bytes to the FDT session \" + sessionID);\n        }\n\n        useFixedBlockSize = (useFixedBlockSize || (this.controlChannel.remoteConf.get(\"-fbs\") != null));\n        localLoop = (localLoop || (this.controlChannel.remoteConf.get(\"-ll\") != null));\n        isLoop = (isLoop || (this.controlChannel.remoteConf.get(\"-loop\") != null));\n        final boolean isRemoteNetTest = (controlChannel.remoteConf.get(\"-nettest\") != null);\n        final boolean isLocalNetTest = config.isNetTest();\n        isNetTest = (isLocalNetTest || isRemoteNetTest);\n\n        if (isNetTest) {\n            logger.log(\n                    Level.INFO,\n                    \"\\n\\n FDT started with \"\n                            + ((isLocalNetTest) ? \"local\" : \"remote\")\n                            + \" -nettest flag. Only network benchmark will be performed. The source and destination are *ignored*!\\n\");\n        }\n\n        if (writeMode == null) {\n            writeMode = (String) this.controlChannel.remoteConf.get(\"-writeMode\");\n        }\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"\\n --> Fixed size blocks: \" + useFixedBlockSize + \" localLoop: \" + localLoop\n                    + \" for fdtSession: \" + sessionID + \" <---\\n\");\n        }\n\n        monitoringTask = new FDTSessionMonitoringTask(this);\n        ScheduledExecutorService monitoringService = Utils.getMonitoringExecService();\n        monitoringTaskFuture = monitoringService.scheduleWithFixedDelay(monitoringTask, 1, 5, TimeUnit.SECONDS);\n\n        monitoringTask.startSession();\n    }\n\n    private void syncFDTConfig(Map<String, Object> remoteConf) {\n\n        if (remoteConf.get(\"-opentsdb\") != null){\n            if(config.getFDTTag() != remoteConf.get(\"-fdtTAG\") && remoteConf.get(\"-fdtTAG\") != null) {\n                config.setFDTTag((String)remoteConf.get(\"-fdtTAG\"));\n            }\n            if (config.getOpentsdb() != remoteConf.get(\"-opentsdb\") && remoteConf.get(\"-opentsdb\") != null) {\n                config.setOpentsdb((String)remoteConf.get(\"-opentsdb\"));\n            }\n            try {\n                FDT.initOpenTSDB(config);\n            } catch (Exception e) {\n                logger.log(Level.WARNING, \"Failed to initOpenTSDB monitor task\", e);\n            }\n        }\n    }\n\n    public int getTransferPort() {\n        return transferPort;\n    }\n\n    public FDTSession(ControlChannel controlChannel, short role) throws Exception {\n        // it is possible to throw a NPE?\n        super(controlChannel.fdtSessionID());\n        customLog = Utils.isCustomLog();\n\n        currentStatus = 0;\n\n        setCurrentState(STARTED);\n        this.controlChannel = controlChannel;\n        this.role = role;\n\n        this.totalProcessedBytes = new AtomicLong(0);\n        this.totalUtilBytes = new AtomicLong(0);\n\n        rateLimit.set(config.getRateLimit());\n        rateLimitDelay.set(config.getRateLimitDelay());\n        final long remoteRateLimit = Utils.getLongValue(controlChannel.remoteConf, \"-limit\", -1);\n        setNewRateLimit(remoteRateLimit, false);\n\n        if (rateLimit.get() > 0) {\n            logger.log(Level.INFO, \"Adding rate limit \" + rateLimit + \" bytes to the FDT session \" + sessionID);\n        }\n\n        useFixedBlockSize = (useFixedBlockSize || (this.controlChannel.remoteConf.get(\"-fbs\") != null));\n        localLoop = (localLoop || (this.controlChannel.remoteConf.get(\"-ll\") != null));\n        isLoop = (isLoop || (this.controlChannel.remoteConf.get(\"-loop\") != null));\n        final boolean isRemoteNetTest = (controlChannel.remoteConf.get(\"-nettest\") != null);\n        final boolean isLocalNetTest = config.isNetTest();\n        isNetTest = (isLocalNetTest || isRemoteNetTest);\n\n        if (isNetTest) {\n            logger.log(\n                    Level.INFO,\n                    \"\\n\\n FDT started with \"\n                            + ((isLocalNetTest) ? \"local\" : \"remote\")\n                            + \" -nettest flag. Only network benchmark will be performed. The source and destination are *ignored*!\\n\");\n        }\n\n        if (writeMode == null) {\n            writeMode = (String) this.controlChannel.remoteConf.get(\"-writeMode\");\n        }\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"\\n --> Fixed size blocks: \" + useFixedBlockSize + \" localLoop: \" + localLoop\n                    + \" for fdtSession: \" + sessionID + \" <---\\n\");\n        }\n\n        monitoringTask = new FDTSessionMonitoringTask(this);\n        ScheduledExecutorService monitoringService = Utils.getMonitoringExecService();\n        monitoringTaskFuture = monitoringService.scheduleWithFixedDelay(monitoringTask, 1, 5, TimeUnit.SECONDS);\n\n        monitoringTask.startSession();\n    }\n\n    public static List<String> getListOfFiles() {\n        logger.log(Level.FINEST, \" [ getListOfFiles ] \");\n        File[] filesList = new File(config.getListFilesFrom()).listFiles();\n        List<String> listOfFiles = new ArrayList<>();\n\n        if (filesList != null) {\n            for (File fileInDir : filesList) {\n                if (fileInDir.canRead()) {\n                    listOfFiles.add(getFileListEntry(fileInDir));\n                }\n            }\n        }\n        logger.log(Level.FINEST, \" [ getListOfFiles ] file list collected from directory: \" + config.getListFilesFrom());\n        return listOfFiles;\n    }\n\n    private static String getFileListEntry(File fileInDir) {\n\n        StringBuilder sb = new StringBuilder();\n        try {\n            PosixFileAttributes fa = Files.readAttributes(fileInDir.toPath(), PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS);\n            sb.append(fa.isDirectory() ? \"d\" : fa.isSymbolicLink() ? \"l\" : fa.isRegularFile() ? \"f\" : \"-\");\n            sb.append(fileInDir.canRead() ? \"r\" : \"-\");\n            sb.append(fileInDir.canWrite() ? \"w\" : \"-\");\n            sb.append(fileInDir.canExecute() ? \"x\" : \"-\");\n            sb.append(\"\\t\");\n            sb.append(fa.owner());\n            sb.append(fa.owner().getName().length() < 4 ? \"\\t\\t\" : \"\\t\");\n            sb.append(fa.group());\n            sb.append(fa.group().getName().length() < 4 ? \"\\t\\t\" : \"\\t\");\n            sb.append(fa.size());\n            sb.append(String.valueOf(fa.size()).length() < 4 ? \"\\t\\t\" : \"\\t\");\n            sb.append(fa.lastModifiedTime().toString());\n            sb.append(\"\\t\");\n            sb.append(fa.isDirectory() ? fileInDir.getName() + \"/\" : fileInDir.getName());\n        } catch (IOException e) {\n            logger.log(Level.WARNING, \"Failed to get file attributes\", e);\n        }\n        logger.info(sb.toString());\n        return sb.toString();\n    }\n\n    final void startControlThread() {\n        if (ctrlThreadStarted.compareAndSet(false, true)) {\n            new Thread(this.controlChannel, \"Control channel for [ \" + config.getHostName() + \":\" + transferPort\n                    + \" ]\").start();\n        }\n    }\n\n    public String getMonID() {\n        return monID;\n    }\n\n    public FDTSessionMonitoringTask getMonitoringTask() {\n        return monitoringTask;\n    }\n\n    public final void setNewRateLimit(final long newRate, boolean ctrlSet) {\n\n        long cLimit = rateLimit.get();\n\n        if (ctrlSet) {\n            cLimit = newRate;\n        } else {\n            if ((newRate != cLimit) && (newRate > 0)) {\n                cLimit = newRate;\n            }\n        }\n\n        if ((cLimit > 0) && (cLimit < Config.NETWORK_BUFF_LEN_SIZE)) {\n            cLimit = Config.NETWORK_BUFF_LEN_SIZE;\n            logger.log(Level.WARNING, \" The rate limit is too small. It will be set to \" + rateLimit.get() + \" Bytes/s\");\n        }\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"[ FDTSession ] [ setNewRateLimit ( \" + newRate + \" ) ] prevRateLimit: \"\n                    + rateLimit.get() + \" newRateLimit: \" + cLimit);\n        }\n\n        rateLimit.set(cLimit);\n    }\n\n    protected final void setCurrentState(int newState) {\n        synchronized (ctrlNotifLock) {\n            try {\n                if (this.currentState == END_RCV) {\n                    // it's very likely that smth gone bad?\n                    return;\n                }\n                this.currentState = newState;\n                this.historyState |= newState;\n            } finally {\n                ctrlNotifLock.notifyAll();\n            }\n        }\n    }\n\n    public final int currentState() {\n        return currentState;\n    }\n\n    public void setMD5Sum(UUID fileSessionID, byte[] md5Sum) {\n        synchronized (md5Sums) {\n            md5Sums.put(fileSessionID, md5Sum);\n        }\n    }\n\n    public short getCurrentStatus() {\n        return currentStatus;\n    }\n\n    protected final int historyState() {\n        return historyState;\n    }\n\n    public TCPTransportProvider getTransportProvider() {\n        return transportProvider;\n    }\n\n    public InetAddress getRemoteAddress() {\n        return controlChannel.remoteAddress;\n    }\n\n    public int getRemotePort() {\n        return controlChannel.remotePort;\n    }\n\n    /**\n     * returns the rate in Bytes/s\n     */\n    public long getRateLimit() {\n        return rateLimit.get();\n    }\n\n    public long getRateLimitDelay() {\n        return rateLimitDelay.get();\n    }\n\n    public int getLocalPort() {\n        return controlChannel.localPort;\n    }\n\n    @Override\n    public String toString() {\n        return \"FDTSession ( \" + sessionID + \" ) / \" + ((controlChannel != null) ? controlChannel.toString() : \"null\");\n    }\n\n    public FileSession getFileSession(UUID fileSessionID) {\n        return fileSessions.get(fileSessionID);\n    }\n\n    public abstract void handleInitFDTSessionConf(final CtrlMsg ctrlMsg) throws Exception;\n\n    public abstract void handleFinalFDTSessionConf(final CtrlMsg ctrlMsg) throws Exception;\n\n    public abstract void handleStartFDTSession(final CtrlMsg ctrlMsg) throws Exception;\n\n    public abstract void handleEndFDTSession(final CtrlMsg ctrlMsg) throws Exception;\n\n    @Override\n    public final void notifyCtrlMsg(ControlChannel controlChannel, Object o) throws FDTProcolException {\n\n        if (o == null) {\n            FDTProcolException fpe = new FDTProcolException(\"Null control message\");\n            fpe.fillInStackTrace();\n            close(\"FileProtocolException\", fpe);\n            throw fpe;\n        }\n\n        try {\n            if (o instanceof CtrlMsg) {\n                CtrlMsg ctrlMsg = (CtrlMsg) o;\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" Got CtrlMessage for \" + controlChannel + \":\\n\" + ctrlMsg);\n                }\n                synchronized (protocolLock) {\n                    switch (ctrlMsg.tag) {\n\n                        case CtrlMsg.INIT_FDTSESSION_CONF: {\n                            setCurrentState(INIT_CONF_RCV);\n                            handleInitFDTSessionConf(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.FINAL_FDTSESSION_CONF: {\n                            setCurrentState(FINAL_CONF_RCV);\n                            handleFinalFDTSessionConf(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.START_SESSION: {\n                            setCurrentState(START_RCV);\n                            handleStartFDTSession(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.END_SESSION: {\n                            setCurrentState(END_RCV);\n                            handleEndFDTSession(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.THIRD_PARTY_COPY: {\n                            setCurrentState(COORDINATOR_MSG_RCVD);\n                            handleCoordinatorMessage(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.LIST_FILES: {\n                            setCurrentState(LIST_FILES_MSG_RCVD);\n                            handleListFilesMessage(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.REMOTE_TRANSFER_PORT: {\n                            setCurrentState(COORDINATOR_MSG_RCVD);\n                            handleGetRemoteTransferPortMessage(ctrlMsg);\n                            break;\n                        }\n                        case CtrlMsg.FILE_NOT_FOUND: {\n                            setCurrentState(MISSING_FILE);\n                            handleFileNotFound(ctrlMsg);\n                            break;\n                        }\n                        default: {\n                            FDTProcolException fpe = new FDTProcolException(\"Illegal CtrlMsg tag [ \" + ctrlMsg.tag + \" ]\");\n                            fpe.fillInStackTrace();\n                            close(\"FileProtocolException\", fpe);\n                            throw fpe;\n                        }\n                    }\n                }\n            } else {\n                logger.log(Level.WARNING, \" Got unknown message on control channel\", o);\n            }\n        } catch (Throwable t) {\n            close(\"Got exception trying to process\", t);\n        }\n    }\n\n    private void handleFileNotFound(CtrlMsg ctrlMsg) {\n        logger.log(Level.WARNING, \"[ FDTSession ] [ handleFileNotFound File not found:  ( \" + ctrlMsg.message.toString() + \" )\");\n    }\n\n    private void handleCoordinatorMessage(CtrlMsg ctrlMsg) {\n\n        logger.log(Level.INFO, \"[ FDTSession ] [ handleCoordinatorMessage ( \" + ctrlMsg.message.toString() + \" )\");\n        Map<String, Object> oldConfig = config.getConfigMap();\n        try {\n            FDTSessionConfigMsg sessionConfig = (FDTSessionConfigMsg) ctrlMsg.message;\n            config.setDestinationDir(sessionConfig.destinationDir);\n            config.setCoordinatorMode(false);\n            config.setDestinationIP(sessionConfig.destinationIP);\n            config.setHostName(sessionConfig.destinationIP);\n            config.setFileList(sessionConfig.fileLists);\n            config.setPortNo(sessionConfig.destinationPort);\n            final ControlChannel ctrlChann = this.controlChannel;\n            int remoteTransferPort = getFDTTransferPort(sessionConfig.destinationPort);\n            if (remoteTransferPort > 0) {\n                FDTSession session = FDTSessionManager.getInstance().addFDTClientSession(remoteTransferPort);\n                ctrlChann.sendSessionIDToCoordinator(new CtrlMsg(CtrlMsg.THIRD_PARTY_COPY, session.controlChannel.fdtSessionID().toString()));\n            } else {\n                ctrlChann.sendSessionIDToCoordinator(new CtrlMsg(CtrlMsg.THIRD_PARTY_COPY, \"-1\"));\n            }\n        } catch (Exception ex) {\n            logger.log(Level.WARNING, \"Exception while handling coordinator message\", ex);\n        } finally {\n            //Restore old config.\n            this.setClosed(true);\n            config.setConfigMap(oldConfig);\n        }\n    }\n\n    public int getFDTTransferPort(int destinationMsgPort) throws Exception {\n        ControlChannel cc = new ControlChannel(config.getHostName(), destinationMsgPort, UUID.randomUUID(), FDTSessionManager.getInstance());\n        int transferPort = cc.sendTransferPortMessage(new CtrlMsg(CtrlMsg.REMOTE_TRANSFER_PORT, \"rtp\"));\n        // wait for remote config\n        logger.log(Level.INFO, \"Got transfer port: \" + config.getHostName() + \":\" + transferPort);\n        return transferPort;\n    }\n\n    private void handleListFilesMessage(CtrlMsg ctrlMsg) {\n        logger.log(Level.INFO, \"[ FDTSession ] [ handleListFilesMessage ( \" + ctrlMsg.message.toString() + \" )\");\n        try {\n            FDTListFilesMsg lsMsg = (FDTListFilesMsg) ctrlMsg.message;\n            config.setListFilesFrom(lsMsg.listFilesFrom);\n            lsMsg.filesInDir = getListOfFiles();\n            logger.log(Level.FINEST, \"[ FDTSession ] [ handleListFilesMessage ] collected \" + lsMsg.filesInDir.size());\n            controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.LIST_FILES, lsMsg));\n            controlChannel.emptyMsgQueue();\n        } catch (Exception ex) {\n            logger.log(Level.WARNING, \"Exception while handling 'list files in dir' message\", ex);\n        } finally {\n            this.setClosed(true);\n        }\n    }\n\n    private void handleGetRemoteTransferPortMessage(CtrlMsg ctrlMsg) {\n        logger.log(Level.INFO, \"[ FDTSession ] [ handleGetRemoteTransferPortMessage ( \" + ctrlMsg.message.toString() + \" )\");\n        try {\n            int newTransferPort = config.getNewRemoteTransferPort();\n            if (newTransferPort > 0) {\n                openSocketForTransferPort(newTransferPort);\n                controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.REMOTE_TRANSFER_PORT, newTransferPort));\n                controlChannel.emptyMsgQueue();\n                this.internalClose();\n                logger.log(Level.INFO, \"[ FDTSession ] [ handleGetRemoteTransferPortMessage ( closing session )\");\n                Utils.waitAndWork(executor, ss, sel, config);\n\n            } else {\n                controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.REMOTE_TRANSFER_PORT, -1));\n                controlChannel.emptyMsgQueue();\n                logger.warning(\"There are no free transfer ports at this moment, please try again later\");\n            }\n        } catch (Exception ex) {\n            logger.log(Level.WARNING, \"Exception while handling 'get remote transfer port' message\", ex);\n        } finally {\n            this.setClosed(true);\n        }\n    }\n\n    private void openSocketForTransferPort(int port) throws IOException {\n\n        executor = Utils.getStandardExecService(\"[ Acceptable ServersThreadPool ] \",\n                2,\n                10,\n                new ArrayBlockingQueue<Runnable>(65500),\n                Thread.NORM_PRIORITY);\n        ssc = ServerSocketChannel.open();\n        ssc.configureBlocking(false);\n        ss = ssc.socket();\n        String listenIP = config.getListenAddress();\n        if (listenIP == null) {\n            ss.bind(new InetSocketAddress(port));\n        }\n        else\n        {\n            ss.bind(new InetSocketAddress(InetAddress.getByName(listenIP), port));\n        }\n\n        sel = Selector.open();\n        ssc.register(sel, SelectionKey.OP_ACCEPT);\n        sc = ssc.accept();\n        config.setSessionSocket(ssc, ss, sc, s, port);\n    }\n\n    protected void buildPartitionMap() {\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \" Building PMap for \" + fileSessions);\n        }\n\n        partitionsMap = new HashMap<Integer, LinkedList<FileSession>>();\n        for (FileSession fs : fileSessions.values()) {\n            if (finishedSessions.contains(fs.sessionID)) {\n                continue;\n            }\n            LinkedList<FileSession> ll = partitionsMap.get(Integer.valueOf(fs.partitionID));\n            if (ll == null) {\n                ll = new LinkedList<FileSession>();\n                partitionsMap.put(Integer.valueOf(fs.partitionID), ll);\n            }\n            ll.add(fs);\n        }\n    }\n\n    public void finishFileSession(UUID sessionID, Throwable downCause) {\n        FileSession fs = null;\n        final boolean bFinest = logger.isLoggable(Level.FINEST);\n        final boolean bFiner = bFinest || logger.isLoggable(Level.FINER);\n        final boolean bFine = bFiner || logger.isLoggable(Level.FINE);\n\n        synchronized (lock) {\n            fs = fileSessions.get(sessionID);\n\n            if (fs != null) {\n                if (!isLoop) {\n                    if (!finishedSessions.add(sessionID)) {\n                        if (bFine) {\n                            logger.log(Level.FINE, \" [ FDTSession ] [ HANDLED ] The fileSession [ \" + sessionID\n                                    + \" ] is already in the finised sessions list\");\n                        }\n                        if (bFinest) {\n                            Thread.dumpStack();\n                        }\n                    } else {\n                        if (downCause == null) {\n                            logger.log(Level.INFO, fs.fileName + \" STATUS: OK\");\n                        }\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \" [ FDTSession ] [ HANDLED ] The fileSession [ \" + sessionID\n                                    + \" ] added to finised sessions list\");\n                        }\n                    }\n                } else {\n                    if (bFiner) {\n                        logger.log(Level.FINER, \" I was supposed to finish ( \" + sessionID\n                                + \" ], but runnig in loop mode\");\n                    }\n                }\n            }\n\n            if (downCause != null) {\n                logger.log(Level.WARNING, fs.fileName + \" STATUS: FAILED\");\n                close(\"the file session: \" + sessionID + \" / \" + fs.fileName + \" finished with errors: \"\n                        + downCause.getMessage(), downCause);\n            }\n        } // end sync\n        try {\n            if (fs != null) {\n                fs.close(null, downCause);\n            } else {\n                logger.log(Level.WARNING, \" The session [ \" + sessionID + \" ] is not in my session list\");\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" Got exception closing file session \" + fs, t);\n        }\n    }\n\n    public boolean useFixedBlockSize() {\n        return useFixedBlockSize;\n    }\n\n    public boolean localLoop() {\n        return localLoop;\n    }\n\n    public boolean loop() {\n        return isLoop;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof FDTSession)) {\n            return false;\n        }\n\n        return this.sessionID.equals(((FDTSession) obj).sessionID);\n    }\n\n    @Override\n    public int hashCode() {\n        return this.sessionID.hashCode();\n    }\n\n    @Override\n    public int compareTo(FDTSession fdtSession) {\n        return this.sessionID.compareTo(fdtSession.sessionID);\n    }\n\n    @Override\n    public long getUtilBytes() {\n        return totalUtilBytes.get();\n    }\n\n    @Override\n    public long getTotalBytes() {\n        return totalProcessedBytes.get();\n    }\n\n    @Override\n    public long addAndGetUtilBytes(long delta) {\n        return totalUtilBytes.addAndGet(delta);\n    }\n\n    @Override\n    public long addAndGetTotalBytes(long delta) {\n        return totalProcessedBytes.addAndGet(delta);\n    }\n\n    @Override\n    public abstract long getSize();\n\n    @Override\n    protected void internalClose() throws Exception {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"FDTSession \" + sessionID + \" finished. Internal close called.\");\n        }\n\n        if ((downCause() != null) && (downMessage() != null)) {\n            currentStatus = 1;\n        } else {\n            currentStatus = 0;\n        }\n\n        // internalClose() is ALWAYS called with the closeLock taken\n        if (monitoringTaskFuture != null) {\n            monitoringTaskFuture.cancel(false);\n        }\n\n        if (monitoringTask != null) {\n            final ScheduledThreadPoolExecutor monitoringService = Utils.getMonitoringExecService();\n            monitoringService.remove(monitoringTask);\n            monitoringService.purge();\n            monitoringTask.finishSession();\n        }\n        if (config.getMonitor().equals(Config.OPENTSDB)) {\n            MonitoringUtils monUtils = new MonitoringUtils(config, this);\n            monUtils.monitorFinish(System.currentTimeMillis(), role == CLIENT ? \"Readers\" : \"Writers\");\n        }\n    }\n\n    /**\n     * @param controlChannel\n     */\n    @Override\n    public void notifyCtrlSessionDown(ControlChannel controlChannel, Throwable cause) {\n        close(\"ControlChannel is down\", cause);\n    }\n\n    @Override\n    public void notifyLisaCtrlMsg(String lisaCtrlMsg) {\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \"FDT Session [ \" + sessionID + \" / \" + monID + \" ] received remote ctrl cmd: \"\n                    + lisaCtrlMsg);\n        }\n\n        if (lisaCtrlMsg.indexOf(LISA_RATE_LIMIT_CMD) >= 0) {\n            long newLimit = -1L;\n            try {\n                newLimit = Long.parseLong(lisaCtrlMsg.split(\"(\\\\s)+\")[1]);\n            } catch (Throwable t) {\n                logger.log(Level.INFO,\n                        \"FDT Session [ \" + sessionID + \" / \" + monID + \" ] unable to set new rate limit\", t);\n            }\n\n            final long oldRateLimit = rateLimit.get();\n\n            if (newLimit > 0) {\n                setNewRateLimit(newLimit, true);\n            }\n\n            if (oldRateLimit != rateLimit.get()) {\n                logger.log(Level.INFO, \"FDT Session [ \" + sessionID + \" / \" + monID + \" ] oldrate: \" + oldRateLimit\n                        + \" / newrate: \" + rateLimit.get());\n            }\n        }\n    }\n\n    public boolean isNetTest() {\n        return isNetTest;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FDTSessionManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.AbstractFDTCloseable;\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.transport.ControlChannel;\nimport lia.util.net.copy.transport.ControlChannelNotifier;\nimport lia.util.net.copy.transport.FDTProcolException;\n\nimport java.nio.channels.SocketChannel;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.UUID;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is the placeholder for all the alve FDTSessions instantiated\n * in the entire FDT app\n *\n * @author ramiro\n */\npublic class FDTSessionManager extends AbstractFDTCloseable implements ControlChannelNotifier {\n\n    private static final Logger logger = Logger.getLogger(FDTSessionManager.class.getName());\n\n    private static final FDTSessionManager _thisInstanceManager = new FDTSessionManager();\n    private static final Config config = Config.getInstance();\n\n    //the map with all the FDT sessions\n    private final Map<UUID, FDTSession> fdtSessionMap;\n\n    //used to wait for the sessions to finish\n    private final Lock lock;\n    private final Condition isSessionMapEmpty;\n\n    //at least one session started\n    private final AtomicBoolean inited;\n\n    private volatile String lastDownMsg;\n    private volatile Throwable lastDownCause;\n\n    private FDTSessionManager() {\n        lock = new ReentrantLock();\n        isSessionMapEmpty = lock.newCondition();\n        fdtSessionMap = new ConcurrentHashMap<>();\n        inited = new AtomicBoolean(false);\n    }\n\n    public static FDTSessionManager getInstance() {\n        return _thisInstanceManager;\n    }\n\n    public void addFDTClientSession(ControlChannel controlChannel) throws Exception {\n\n        FDTSession fdtSession = null;\n        try {\n            if (controlChannel.remoteConf.get(\"-pull\") != null) {\n                //-> Start a reader and connect to the server\n                fdtSession = new FDTReaderSession(controlChannel);\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \" Adding FDTReaderSession ( \" + fdtSession.sessionID\n                            + \" ) to the FDTSessionManager\");\n                }\n            } else {\n                //-> Start a writer and connect to the server\n                fdtSession = new FDTWriterSession(controlChannel);\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \" Adding FDTWriterSession ( \" + fdtSession.sessionID\n                            + \" ) to the FDTSessionManager\");\n                }\n            }\n\n            fdtSessionMap.put(fdtSession.sessionID(), fdtSession);\n            inited.set(true);\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" Got exception instantiate Session/RemoteConn \", t);\n\n            //close the session\n            Utils.closeIgnoringExceptions(fdtSession, \"Exception instantiate Session/RemoteConn\", t);\n\n            //and the control channel\n            Utils.closeIgnoringExceptions(controlChannel, \"Exception instantiate Session/RemoteConn\", t);\n\n            throw new Exception(t);\n        }\n    }\n\n    //called from\n    public FDTSession addFDTClientSession(int transferPort) throws Exception {\n\n        FDTSession fdtSession = null;\n\n        try {\n            if (config.isPullMode()) {\n                //-> Start a writer and connect to the server\n                fdtSession = new FDTWriterSession(transferPort);\n            } else {\n                //-> Start a reader and connect to the server\n                fdtSession = new FDTReaderSession(transferPort);\n            }\n\n            fdtSessionMap.put(fdtSession.sessionID(), fdtSession);\n            inited.set(true);\n\n            //I may start the control thread now; FindBugs suggestion\n            fdtSession.startControlThread();\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception initiation Session/RemoteConn \", t);\n\n            Utils.closeIgnoringExceptions(fdtSession, \"Got exception initiation Session/RemoteConn \", t);\n\n            throw new Exception(t);\n        }\n        return fdtSession;\n    }\n\n    public int sessionsNumber() {\n        return fdtSessionMap.size();\n    }\n\n    public boolean isInited() {\n        return inited.get();\n    }\n\n    public FDTSession getSession(UUID fdtSessionID) {\n        return fdtSessionMap.get(fdtSessionID);\n    }\n\n    public boolean finishSession(UUID fdtSessionID, String downMessage, Throwable downCause) {\n        final FDTSession fdtSession = fdtSessionMap.remove(fdtSessionID);\n        //fdtSession.setClosed(true);\n        logger.log(Level.FINER, \" FDTSessionManager removed sessionID \" + fdtSessionID + \"; removed == \"\n                + (fdtSession != null) + \" new size: \" + fdtSessionMap.size());\n        //I know ... it's not very well sync, but should be enough for the client side ... which will have only one FDT Session\n        if (fdtSessionMap.size() == 0) {\n            lock.lock();\n            try {\n\n                lastDownMsg = downMessage;\n                lastDownCause = downCause;\n\n                isSessionMapEmpty.signalAll();\n            } finally {\n                lock.unlock();\n            }\n        }\n\n        if (fdtSession == null) {\n            return false;\n        }\n\n        return fdtSession.close(downMessage, downCause);\n    }\n\n    public void addWorker(final UUID fdtSessionID, final SocketChannel sc) throws Exception {\n        final FDTSession fdtSession = fdtSessionMap.get(fdtSessionID);\n        if (fdtSession != null) {\n            fdtSession.transportProvider.addWorkerStream(sc, true);\n        } else {\n            logger.log(Level.WARNING, \"\\n\\n [ FDTSessionManager ] No such session \" + fdtSessionID + \" for worker: \"\n                    + sc + \". The channel will be closed\");\n            Utils.closeIgnoringExceptions(sc);\n        }\n    }\n\n    public void notifyCtrlMsg(ControlChannel controlChannel, Object o) throws FDTProcolException {\n        if (controlChannel == null) {\n            throw new NullPointerException(\"ControlChannel cannot be null in notifier!\");\n        }\n\n        final FDTSession fdtSession = fdtSessionMap.get(controlChannel.fdtSessionID());\n        if (fdtSession == null) {\n            throw new FDTProcolException(\"No FDTSession for ID: \" + controlChannel.fdtSessionID());\n        }\n\n        fdtSession.notifyCtrlMsg(controlChannel, o);\n    }\n\n    public void awaitTermination() throws InterruptedException {\n        lock.lock();\n        try {\n            while (fdtSessionMap.size() > 0) {\n                isSessionMapEmpty.await(5, TimeUnit.SECONDS);\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" waiting for [ \" + fdtSessionMap.size() + \" ] sessions to finish. -> \"\n                            + Arrays.toString(fdtSessionMap.keySet().toArray(new UUID[0])));\n                }\n            }\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public Throwable getLasDownCause() {\n        lock.lock();\n        try {\n            return lastDownCause;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public String getLasDownMessage() {\n        lock.lock();\n        try {\n            return lastDownMsg;\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    public void notifyCtrlSessionDown(ControlChannel controlChannel, Throwable cause) {\n        final FDTSession fdtSession = fdtSessionMap.get(controlChannel.fdtSessionID());\n        if (fdtSession != null) {\n            fdtSession.notifyCtrlSessionDown(controlChannel, cause);\n        }\n    }\n\n    @Override\n    protected void internalClose() throws Exception {\n\n    }\n}"
  },
  {
    "path": "src/lia/util/net/copy/FDTWriterSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.*;\nimport lia.util.net.copy.disk.DiskWriterManager;\nimport lia.util.net.copy.disk.ResumeManager;\nimport lia.util.net.copy.filters.Postprocessor;\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\nimport lia.util.net.copy.transport.*;\n\nimport java.io.File;\nimport java.net.InetAddress;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.*;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The Writer session ...\n *\n * @author ramiro\n */\npublic class FDTWriterSession extends FDTSession implements FileBlockConsumer {\n\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(FDTWriterSession.class.getName());\n\n    private static final ResumeManager resumeManager = ResumeManager.getInstance();\n\n    private static final Config config = Config.getInstance();\n\n    private static final DiskWriterManager dwm = DiskWriterManager.getInstance();\n    private final AtomicBoolean finalCleaupExecuted = new AtomicBoolean(false);\n    private final AtomicBoolean finishNotifiedExecuted = new AtomicBoolean(false);\n    private String destinationDir;\n    private String[] fileList;\n    private ProcessorInfo processorInfo;\n\n    public FDTWriterSession(int transferPort) throws Exception {\n        super(FDTSession.CLIENT, transferPort);\n        Utils.initLogger(config.getLogLevel(), new File(System.getProperty(\"java.io.tmpdir\") + File.separatorChar + sessionID + \".log\"), new Properties());\n        dwm.addSession(this);\n        sendInitConf();\n        this.monID = config.getMonID();\n    }\n\n    /**\n     * REMOTE SESSION\n     *\n     * @param cc control channel\n     * @throws Exception\n     */\n    public FDTWriterSession(ControlChannel cc) throws Exception {\n        super(cc, FDTSession.SERVER);\n        Utils.initLogger(config.getLogLevel(), new File(\"/tmp/\" + sessionID + \".log\"), new Properties());\n        dwm.addSession(this);\n        this.monID = (String) cc.remoteConf.get(\"-monID\");\n    }\n\n    public void setControlChannel(ControlChannel controlChannel) {\n        this.controlChannel = controlChannel;\n    }\n\n    public void notifyWriterDown(int partitionID) {\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \"[FDTWriterSession] writer down for partition: \" + partitionID);\n        }\n    }\n\n    private void notifySessionFinished() {\n\n        if (finishNotifiedExecuted.compareAndSet(false, true)) {\n            StringBuilder downNotif = null;\n\n            try {\n                if (downMessage() != null && downCause() != null) {\n\n                    downNotif = new StringBuilder();\n\n                    if (downMessage() != null) {\n                        downNotif.append(\"Down message: \").append(downMessage()).append(\"\\n\");\n                    }\n\n                    if (downCause() != null) {\n                        downNotif.append(\"Down cause:\\n\").append(Utils.getStackTrace(downCause())).append(\"\\n\");\n                    }\n                }\n            } catch (Throwable t1) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE,\n                            \"[ FDTWriterSession ] [ notifySessionFinished ]  Got exception building the remote notify message\",\n                            t1);\n                }\n            }\n\n            try {\n                controlChannel.sendCtrlMessage(\n                        new CtrlMsg(CtrlMsg.END_SESSION, (downNotif == null) ? null : downNotif.toString()));\n            } catch (Throwable t1) {\n                logger.log(Level.WARNING,\n                        \" [ FDTWriterSession ] [ notifySessionFinished ] got exception sending END_SESSION message\",\n                        t1);\n            }\n        }\n    }\n\n    private void finalCleanup() {\n\n        if (finalCleaupExecuted.compareAndSet(false, true)) {\n\n            final boolean isFinest = logger.isLoggable(Level.FINEST);\n            final boolean isFiner = isFinest || logger.isLoggable(Level.FINER);\n            final boolean isFine = isFiner || logger.isLoggable(Level.FINE);\n\n            if (isFiner) {\n                logger.log(Level.FINER, \"\\n\\n [ FDTWriterSession ] [ finalCleanup ] STARTED \\n\\n \");\n            }\n\n            // for logging the time the transfer completed\n            final Date endDate = new Date();\n\n            NetloggerRecord nlrec = new NetloggerRecord();\n            nlrec.setBlock(DirectByteBufferPool.getInstance().getBufferSize());\n            nlrec.setBuffer(Math.max(0, config.getSockBufSize()));\n            if (downCause() == null && downMessage() == null) {\n                nlrec.setCode(\"226\");  // = \"Closing data connection. Requested file action successful.\"\n            } else {\n                nlrec.setCode(\"426\");  // = \"Connection closed; transfer aborted.\"\n            }\n            nlrec.setCompleted(endDate);\n            nlrec.setDestination(controlChannel.remoteAddress);\n            try {\n                nlrec.setHost(InetAddress.getLocalHost());\n            } catch (java.net.UnknownHostException ex) {\n                /* do nothing */\n            }\n            nlrec.setNbytes(getTotalBytes());\n            nlrec.setStart(new Date(startTimeMillis));\n            if (getTransportProvider() != null) {\n                nlrec.setStreams(getTransportProvider().getNumberOfStreams());\n            }\n            nlrec.setType(\"STOR\");\n\n            logger.info(nlrec.toULMString());\n\n            try {\n                notifySessionFinished();\n            } catch (Throwable ignore) {\n                if (isFinest) {\n                    logger.log(Level.FINEST,\n                            \"[ FDTWriterSession ] [ finalCleanup ] exception notify session finished. Cause:\", ignore);\n                }\n            }\n\n            try {\n\n                final StringBuilder sb = new StringBuilder();\n                sb.append(\"\\n\\nFDTWriterSession ( \").append(sessionID);\n                if (monID != null) {\n                    sb.append(\" / \").append(monID);\n                }\n                sb.append(\" ) final stats:\");\n                sb.append(\"\\n Started: \").append(new Date(startTimeMillis));\n                sb.append(\"\\n Ended:   \").append(endDate);\n                long period = System.nanoTime() - startTimeNanos;\n                sb.append(\"\\n Transfer period:   \")\n                        .append(Utils.getETA(TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTimeNanos)));\n                sb.append(\"\\n TotalBytes: \").append(getTotalBytes());\n                long utilBytes = 0;\n                if (transportProvider != null) {\n                    utilBytes = transportProvider.getUtilBytes();\n                    sb.append(\"\\n TotalNetworkBytes: \").append(transportProvider.getUtilBytes());\n                    try {\n                        if (!Utils.updateTotalReadCounter(transportProvider.getUtilBytes())) {\n                            if (logger.isLoggable(Level.FINEST)) {\n                                logger.log(Level.FINEST,\n                                        \" [ FDTWriterSession ] Unable to update the contor in the update file.\");\n                            }\n                        }\n                    } catch (Throwable tu) {\n                        if (logger.isLoggable(Level.FINEST)) {\n                            logger.log(Level.FINEST,\n                                    \" [ FDTWriterSession ] Unable to update the contor in the update file. Cause: \",\n                                    tu);\n                        }\n                    } finally {\n                        transportProvider.close(downMessage(), downCause());\n                    }\n                } else {\n                    sb.append(\"\\n TotalNetworkBytes: 0\");\n                }\n                sb.append(\"\\n Exit Status: \").append((downCause() == null && downMessage() == null) ? \"OK\" : \"Not OK\");\n                sb.append(\"\\n\");\n                if (customLog) {\n                    logger.info(sb.toString());\n                } else {\n                    System.out.println(sb.toString());\n                }\n                if (config.getMonitor().equals(Config.OPENTSDB)) {\n                    MonitoringUtils monUtils = new MonitoringUtils(config, this);\n                    monUtils.monitorEndStats(((downCause() == null) && (downMessage() == null)), getTotalBytes(), utilBytes,\n                            startTimeMillis,  endDate.getTime(), period, \"Writers\");\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING,\n                        \"[ FDTWriterSession ] [ finalCleanup ] [ HANDLED ] Exception getting final statistics. Smth went wrong! Cause: \",\n                        t);\n            }\n\n            try {\n                if (dwm.removeSession(this, downMessage(), downCause())) {\n                    if (isFine) {\n                        logger.log(Level.FINE,\n                                \"[ FDTWriterSession ] [ finalCleanup ] Successfully removing session from DiskWriterManager\");\n                    }\n                } else {\n                    if (isFine) {\n                        logger.log(Level.FINE,\n                                \"[ FDTWriterSession ] [ finalCleanup ] Removing session from DiskWriterManager returned FALSE should have been true!!\");\n                    }\n                }\n            } catch (Throwable fine) {\n                if (isFine) {\n                    logger.log(Level.FINE, \"[ FDTWriterSession ] [ finalCleanup ] exception removing session. Cause:\",\n                            fine);\n                }\n            }\n\n            try {\n                for (final FileSession fileSession : fileSessions.values()) {\n                    try {\n                        fileSession.close(downMessage(), downCause());\n                    } catch (Throwable ign) {\n                        if (isFinest) {\n                            logger.log(Level.FINEST, \"[ FDTWriterSession ] [ finalCleanup ]  closing file session: \"\n                                    + fileSession + \" got exception. Cause: \", ign);\n                        }\n                    }\n                }\n            } catch (Throwable ignOutter) {\n                if (isFinest) {\n                    logger.log(Level.FINEST,\n                            \"[ FDTWriterSession ] [ finalCleanup ]  closing file sessions got exception. Cause: \",\n                            ignOutter);\n                }\n            }\n\n            try {\n                doPostProcessing();\n            } catch (Throwable t1) {\n                logger.log(Level.WARNING, \"[ FDTWriterSession ] [ finalCleanup  Got exception in postProcessing\", t1);\n            }\n\n            try {\n                if (transportProvider != null) {\n                    transportProvider.close(downMessage(), downCause());\n                }\n            } catch (Throwable ignTransport) {\n                if (isFinest) {\n                    logger.log(Level.FINEST,\n                            \"[ FDTWriterSession ] [ finalCleanup ]  closing transport got exception. Cause: \",\n                            ignTransport);\n                }\n            }\n\n            try {\n                if (controlChannel != null) {\n                    controlChannel.close(downMessage(), downCause());\n                }\n            } catch (Throwable ignCtrl) {\n                if (isFinest) {\n                    logger.log(Level.FINEST,\n                            \"[ FDTWriterSession ] [ finalCleanup ]  closing control channel got exception. Cause: \",\n                            ignCtrl);\n                }\n            }\n            try {\n                FDTSessionManager.getInstance().finishSession(sessionID, downMessage(), downCause());\n            } catch (Throwable ignore) {\n                if (isFinest) {\n                    logger.log(Level.FINEST,\n                            \"[ FDTWriterSession ] [ finalCleanup ]  finishing session in session manager got exception. Cause: \",\n                            ignore);\n                }\n            }\n        }\n    }\n\n    protected void internalClose() throws Exception {\n\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n            logger.log(Level.FINEST, \" [ FDTWriterSession ] enters internalClose downMsg: \" + downMessage()\n                    + \" ,  downCause: \" + downCause());\n            Thread.dumpStack();\n        }\n\n        try {\n            super.internalClose();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ FDTWriterSession ] [ HANDLED ] internalClose exception in base class.\", t);\n        }\n\n        final String downMessage = downMessage();\n        final Throwable downCause = downCause();\n\n        if (downMessage == null && downCause == null) {\n            checkFinished(null);\n        } else {\n            final String downLogMsg = (downMessage == null) ? \"N/A\" : downMessage;\n            logger.log(Level.INFO,\n                    \"\\nThe FDTWriterSession ( \" + sessionID + \" ) finished with error(s). Cause: \" + downLogMsg,\n                    downCause());\n            finalCleanup();\n        }\n\n    }\n\n    private void sendInitConf() throws Exception {\n        FDTSessionConfigMsg sccm = new FDTSessionConfigMsg();\n\n        sccm.destinationDir = config.getDestinationDir();\n        sccm.fileLists = config.getFileList();\n        sccm.remappedFileLists = config.getRemappedFileList();\n        sccm.recursive = config.isRecursive();\n        this.destinationDir = sccm.destinationDir;\n\n        controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.INIT_FDTSESSION_CONF, sccm));\n        setCurrentState(INIT_CONF_SENT);\n    }\n\n    private void sendFinishedSessions() throws Exception {\n        controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.FINAL_FDTSESSION_CONF,\n                finishedSessions.toArray(new UUID[finishedSessions.size()])));\n        setCurrentState(FINAL_CONF_SENT);\n    }\n\n    @Override\n    public void handleInitFDTSessionConf(CtrlMsg ctrlMsg) throws Exception {\n        // this should be never called ( for the moment ... )\n        logger.log(Level.WARNING,\n                \"[ FDTWriterSession ] handleInitFDTSessionConf must not be called on the writer side. Msg: \" + ctrlMsg);\n        FDTProcolException fpe = new FDTProcolException(\"Illegal message INIT_FDT_CONF in WriterSesssion\");\n        fpe.fillInStackTrace();\n        throw fpe;\n    }\n\n    @Override\n    public void handleFinalFDTSessionConf(CtrlMsg ctrlMsg) throws Exception {\n        final boolean isFiner = logger.isLoggable(Level.FINER);\n        config.registerTransferPortForSession(controlChannel.localPort, sessionID().toString());\n        FDTSessionConfigMsg sccm = (FDTSessionConfigMsg) ctrlMsg.message;\n\n        this.destinationDir = sccm.destinationDir;\n\n        // re-assign destination directory if transferring to storage\n        StoragePathDecoder spd = new StoragePathDecoder(sccm.destinationDir, \"\", \"\");\n        if (spd.hasStorageInfo()) {\n            if (config.storageParams() == null) {\n                logger.log(Level.SEVERE, \"Unable to transfer to storage: \" + \"Storage configuration is not found.\");\n            } else {\n                this.destinationDir = config.storageParams().localFileDir();\n                logger.log(Level.WARNING, \"Destination directory has been \" + \"changed from \" + sccm.destinationDir\n                        + \" to \" + this.destinationDir);\n            }\n        }\n\n        this.fileList = new String[sccm.fileLists.length];\n        System.arraycopy(sccm.fileLists, 0, this.fileList, 0, this.fileList.length);\n\n        boolean shouldReplace = false;\n        final char remoteCharSeparator = ((String) controlChannel.remoteConf.get(\"file.separator\")).charAt(0);\n        if (File.separatorChar == '/') {\n            if (remoteCharSeparator == '\\\\') {\n                shouldReplace = true;\n            }\n        }\n\n        // first build the map ... then check for already transfered files\n        int fCount = sccm.fileIDs.length;\n\n        // check for temp file\n        boolean noTmp = false;\n        if (config.isNoTmpFlagSet() || controlChannel.remoteConf.get(\"-notmp\") != null) {\n            noTmp = true;\n        }\n        boolean noLock = false;\n        if (config.isNoLockFlagSet() || controlChannel.remoteConf.get(\"-nolock\") != null\n                || controlChannel.remoteConf.get(\"-nolocks\") != null) {\n            noLock = true;\n        }\n\n        final FileChannelProvider fcp = Config.getInstance().getFileChannelProviderFactory()\n                .newWriterFileChannelProvider(this);\n\n        final String preProcessFiltersProp = config.getPreFilters();\n        boolean hasPreProc = false;\n        String[] preProcessFilters = null;\n\n        if (preProcessFiltersProp == null || preProcessFiltersProp.length() == 0) {\n            if (isFiner) {\n                logger.log(Level.FINE, \"[ FDTWriterSession ] No FDT Preprocess Filters defined\");\n            }\n        } else {\n            // pre-processing is enabled\n            preProcessFilters = preProcessFiltersProp.split(\",\");\n            if (preProcessFilters == null || preProcessFilters.length == 0) {\n                logger.log(Level.WARNING, \"Illegal -preFilters parameter\");\n            } else {\n                hasPreProc = true;\n            }\n        }\n\n        final Map<String, FileSession> preProcMap = (hasPreProc) ? new HashMap<String, FileSession>() : null;\n\n        for (int i = 0; i < fCount; i++) {\n            final String fName = (sccm.remappedFileLists == null || sccm.remappedFileLists[i] == null)\n                    ? sccm.fileLists[i] : sccm.remappedFileLists[i];\n            // OSG change, just get the file name and none of the path stuff\n            Path p = Paths.get(fName);\n            String oFileName = p.getFileName().toString();\n             \t\n            final FileWriterSession fws = new FileWriterSession(sccm.fileIDs[i], this,\n                    this.destinationDir + File.separator\n                            + ((shouldReplace) ? fName.replace(remoteCharSeparator, File.separatorChar) : oFileName),\n                    sccm.fileSizes[i], sccm.lastModifTimes[i], isLoop, writeMode, noTmp, noLock, fcp);\n            fileSessions.put(fws.sessionID, fws);\n            if (hasPreProc) {\n                final FileWriterSession fwsCopy = FileWriterSession.fromFileWriterSession(fws);\n                preProcMap.put(fwsCopy.fileName(), fwsCopy);\n            }\n            setSessionSize(sessionSize() + fws.sessionSize());\n        }\n\n        if (hasPreProc) {\n            final long sTime = System.nanoTime();\n            boolean bPreProccessing = false;\n\n            try {\n                bPreProccessing = doPreprocess(preProcessFilters, preProcMap);\n            } catch (Throwable tPrepProcess) {\n                logger.log(Level.WARNING, \"Got exception preprocessing\", tPrepProcess);\n            }\n\n            if (bPreProccessing) {\n                logger.log(Level.INFO,\n                        \"Preprocessing took: \" + (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sTime)) + \" ms.\");\n            }\n        }\n\n        for (final FileSession fws : fileSessions.values()) {\n            if (resumeManager.isFinished(fws)) {\n                if (isFiner) {\n                    logger.log(Level.FINER,\n                            \"\\n\\n\\n ====> [ FDTWriterSession ] the file session \" + fws.sessionID + \" is Finished!\");\n                }\n                addAndGetUtilBytes(fws.sessionSize());\n                addAndGetTotalBytes(fws.sessionSize());\n                super.finishFileSession(fws.sessionID, null);\n            } else {\n                if (isFiner) {\n                    logger.log(Level.FINER, \"\\n\\n\\n ====> [ FDTWriterSession ] <====== the file session \"\n                            + fws.sessionID + \" is NOT Finished!  <============ \");\n                }\n            }\n        }\n\n        buildPartitionMap();\n        sendFinishedSessions();\n\n        // I will start the transport writer and notify the FDTReader Peer\n        if (role == SERVER) {\n            // just to be sure\n            if (transportProvider == null) {\n                transportProvider = new TCPSessionReader(this, this);\n            } else {\n                throw new FDTProcolException(\" Non null transport provider !\");\n            }\n        } else if (role == CLIENT) {\n            transportProvider = new TCPSessionReader(this, this, InetAddress.getByName(config.getHostName()),\n                    transferPort, config.getSockNum());\n        }\n\n        // Notify the reader that he can start to send the data\n        logger.log(Level.FINER, \"FWS handleFinalFDTSessionConf starting session on port: \" + transferPort);\n        controlChannel.sendCtrlMessage(new CtrlMsg(CtrlMsg.START_SESSION, transferPort));\n\n        setCurrentState(START_SENT);\n\n        checkFinished(null);\n    }\n\n    public long getSize() {\n        return sessionSize();\n    }\n\n    @Override\n    public void handleStartFDTSession(CtrlMsg ctrlMsg) throws Exception {\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \"[ FDTWriterSession ] handleStartFDTSession. Msg: \" + ctrlMsg);\n        }\n        if (role == CLIENT) {\n            if (transportProvider == null) {\n                transportProvider = new TCPSessionReader(this, this, InetAddress.getByName(config.getHostName()),\n                        transferPort, config.getSockNum());\n            }\n        }\n        if (config.getMonitor().equals(Config.OPENTSDB)) {\n            MonitoringUtils monUtils = new MonitoringUtils(config, this);\n            monUtils.monitorStart(System.currentTimeMillis(), \"Writers\");\n        }\n\n        setCurrentState(TRANSFERING);\n        transportProvider.startTransport(true);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public void handleEndFDTSession(CtrlMsg ctrlMsg) throws Exception {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER,\n                    \"\\n\\n\\n\\n\\n\\n ---------------- [ FDTWriterSession ] handleEndFDTSession. Msg: \" + ctrlMsg.message);\n        }\n\n        String remoteDownMsg = null;\n        if (ctrlMsg.message != null) {\n            if (ctrlMsg.message instanceof Map) {\n                logger.log(Level.INFO, \"[ FDTWriterSession ] Remote FDTReaderSession for session [ \" + sessionID\n                        + \" ] finished ok. Waiting for our side to finish.\");\n                // the md5 sums\n                Map<UUID, byte[]> md5Sums = (Map<UUID, byte[]>) ctrlMsg.message;\n\n                if (md5Sums != null && md5Sums.size() > 0) {\n                    StringBuilder sb = new StringBuilder();\n                    sb.append(\"\\n\\n===\\tRemote MD5 Sums\\t===\");\n                    for (Map.Entry<UUID, byte[]> entry : md5Sums.entrySet()) {\n                        sb.append(\"\\n\").append(Utils.md5ToString(entry.getValue())).append(\"  \")\n                                .append(fileSessions.get(entry.getKey()).fileName());\n                    }\n                    sb.append(\"\\n===\\tEND Remote MD5 Sums\\t=== \\n\");\n                    logger.log(Level.INFO, sb.toString());\n                }\n\n            } else if (ctrlMsg.message instanceof String) {\n                remoteDownMsg = (String) ctrlMsg.message;\n                close(remoteDownMsg, null);\n                logger.log(Level.WARNING, \"\\n\\n [ FDTWriterSession ] Remote FDTReaderSession for session [ \" + sessionID\n                        + \" ] finished with errors:\\n\" + remoteDownMsg + \"\\n\");\n            }\n        } else {\n            logger.log(Level.INFO, \"[ FDTWriterSession ] Remote FDTReaderSession for session [ \" + sessionID\n                    + \" ] finished ok. Waiting for our side to finish.\");\n        }\n    }\n\n    private boolean doPreprocess(String[] preProcessFilters, Map<String, FileSession> preProcMap) throws Exception {\n\n        final boolean isFinest = logger.isLoggable(Level.FINEST);\n        final boolean isFiner = isFinest || logger.isLoggable(Level.FINER);\n        final boolean isFine = isFiner || logger.isLoggable(Level.FINE);\n\n        if (isFinest) {\n            logger.log(Level.FINEST, \"[ FDTWriterSession ] entering preprocessing started\");\n        }\n\n        final ProcessorInfo processorInfo = new ProcessorInfo();\n\n        processorInfo.destinationDir = (this.destinationDir == null) ? config.getDestinationDir() : this.destinationDir;\n\n        final Set<UUID> finishedSessions = this.finishedSessions;\n        final boolean bFinishedSessions = finishedSessions.size() > 0;\n        if (bFinishedSessions) {\n            for (final FileSession fws : preProcMap.values()) {\n                final UUID id = fws.sessionID();\n                if (finishedSessions.contains(id)) {\n                    final String fName = fws.fileName();\n                    if (isFinest) {\n                        logger.log(Level.FINEST, \"[FDTWriterSession] [doPreprocess] finished file session: \" + fName);\n                    }\n                    preProcMap.remove(fName);\n                }\n            }\n        }\n\n        final String[] fList = preProcMap.keySet().toArray(new String[preProcMap.size()]);\n        processorInfo.fileList = fList;\n        processorInfo.fileSessionMap = preProcMap;\n        processorInfo.remoteAddress = this.controlChannel.remoteAddress;\n        processorInfo.remotePort = this.controlChannel.remotePort;\n\n        for (final String filterName : preProcessFilters) {\n            Preprocessor preprocessor = (Preprocessor) (Class.forName(filterName).newInstance());\n            preprocessor.preProcessFileList(processorInfo, this.controlChannel.subject);\n        }\n\n        this.processorInfo = processorInfo;\n\n        final Set<UUID> retIDs = new HashSet<UUID>();\n        // overwrite existing sessions\n        for (final FileSession fs : preProcMap.values()) {\n            final UUID fid = fs.sessionID;\n            final FileSession existing = fileSessions.get(fid);\n            if (existing == null) {\n                logger.log(Level.WARNING,\n                        \"[FDTWriterSession] [doPreprocess] new file session from filter will be ingored: \" + fs);\n                continue;\n            }\n\n            if (fs instanceof FileWriterSession) {\n                retIDs.add(fid);\n                fileSessions.put(fid, fs);\n            } else {\n                logger.log(Level.WARNING,\n                        \"[FDTWriterSession] [doPreprocess] new file session from filter will be ingored: \" + fs\n                                + \" because is not a FileWriterSession\");\n            }\n        }\n\n        //check for removed sessions\n        for (final FileSession fws : fileSessions.values()) {\n            final UUID fid = fws.sessionID;\n            if (!retIDs.contains(fid)) {\n                if (isFine) {\n                    logger.log(Level.FINE, \"\\n\\n\\n ====> [ FDTWriterSession ] [preProcess] the file session \"\n                            + fws.sessionID + \"/\" + fws.fileName() + \" is finished!\");\n                }\n                addAndGetUtilBytes(fws.sessionSize());\n                addAndGetTotalBytes(fws.sessionSize());\n                super.finishFileSession(fws.sessionID, null);\n            }\n        }\n\n        // changed since FDT 0.12.0 to return true\n        // before the filter count was checked here\n        return true;\n    }\n\n    private boolean doPostProcessing() throws Exception {\n\n        if (!postProcessingDone.compareAndSet(false, true)) {\n            return false;\n        }\n\n        int filtersCount = 0;\n        final long sTime = System.nanoTime();\n\n        logger.log(Level.INFO, \"[ FDTWriterSession ] Post Processing started\");\n\n        try {\n            ProcessorInfo processorInfo = (this.processorInfo == null) ? new ProcessorInfo() : this.processorInfo;\n            final HashMap<String, FileSession> preprocMap = new HashMap<String, FileSession>();\n\n            final String postProcessFiltersProp = config.getPostFilters();\n\n            // call the postProcessfilter\n            if (postProcessFiltersProp == null || postProcessFiltersProp.length() == 0) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.INFO, \" [ FDTWriterSession ] No FDT Postprocess Filters defined\");\n                }\n            } else {\n                String[] postProcessFilters = postProcessFiltersProp.split(\",\");\n                if (postProcessFilters == null || postProcessFilters.length == 0) {\n                    logger.log(Level.WARNING, \"Cannot understand -postFilters\");\n                } else {\n                    filtersCount = postProcessFilters.length;\n                    for (final FileSession fws : fileSessions.values()) {\n                        preprocMap.put(fws.fileName(), fws);\n                    }\n\n                    final String[] fList = preprocMap.keySet().toArray(new String[preprocMap.size()]);\n                    processorInfo.fileList = fList;\n                    processorInfo.fileSessionMap = new HashMap<String, FileSession>(preprocMap);\n\n                    processorInfo.destinationDir = this.destinationDir;\n\n                    System.arraycopy(fileList, 0, processorInfo.fileList, 0, fileList.length);\n\n                    processorInfo.remoteAddress = this.controlChannel.remoteAddress;\n                    processorInfo.remotePort = this.controlChannel.remotePort;\n\n                    for (final String filterName : postProcessFilters) {\n                        postPprocess(processorInfo, filterName);\n                    }\n                }\n            }\n        } finally {\n            StringBuffer sb = new StringBuffer();\n            if (filtersCount > 0) {\n                sb.append(\"[ FDTWriterSession ] Postprocessing: \").append(filtersCount).append(\" filters in \")\n                        .append(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sTime)).append(\" ms\");\n            } else {\n                sb.append(\"[ FDTWriterSession ] No post processing filters defined/processed.\");\n            }\n            logger.log(Level.INFO, sb.toString());\n        }\n\n        return (filtersCount > 0);\n    }\n\n    private void postPprocess(ProcessorInfo processorInfo, String filterName) throws Exception {\n        boolean searchElsewhere = false;\n        Postprocessor postprocessor = null;\n        try {\n            postprocessor = (Postprocessor) (Class.forName(\"lia.util.net.copy.filters.examples.\" + filterName).newInstance());\n        } catch (ClassNotFoundException e) {\n            searchElsewhere = true;\n        }\n        if (searchElsewhere) {\n            String userDirectory = System.getProperty(\"user.dir\");\n            File filter = new File(userDirectory + File.separator + \"plugins\" + File.separator);\n            logger.log(Level.FINER, \"Trying to load plugin from 'plugins' directory. \" + filter.toString());\n            try {\n                URL url = filter.toURL();\n                URL[] urls = new URL[]{url};\n                ClassLoader cl = new URLClassLoader(urls);\n                Class cls = cl.loadClass(filterName);\n                postprocessor = (Postprocessor) cls.newInstance();\n            } catch (Exception e) {\n                logger.log(Level.FINER, \"Failed to load filter from external plugins directory. \" + e);\n                postprocessor = (Postprocessor) (Class.forName(filterName).newInstance());\n            }\n        }\n        if (postprocessor != null) {\n            postprocessor.postProcessFileList(processorInfo, this.controlChannel.subject, downCause(),\n                    downMessage());\n        }\n    }\n\n    private void checkFinished(Throwable finishCause) {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"\\n\\n\\n\\n\\n\\n ---------------- [ FDTWriterSession ] finishedSessions.size(). \"\n                    + finishedSessions.size() + \" fileSessions.size() \" + fileSessions.size());\n        }\n\n        if (finishedSessions.size() == fileSessions.size()) {\n\n            if (downMessage() != null || downCause() != null) {\n                close(downMessage(), downCause());\n            } else {\n                close(downMessage(), finishCause);\n            }\n\n            notifySessionFinished();\n\n            Runnable finalR = new Runnable() {\n\n                public void run() {\n                    finalCleanup();\n                }\n            };\n\n            Utils.getMonitoringExecService().schedule(finalR, 5, TimeUnit.SECONDS);\n\n        }\n    }\n\n    public void finishFileSession(UUID sessionID, Throwable finishCause) {\n        super.finishFileSession(sessionID, finishCause);\n        checkFinished(finishCause);\n    }\n\n    public boolean offer(final FileBlock fileBlock, long delay, TimeUnit unit) throws InterruptedException {\n        if (isClosed()) {\n            return false;\n        }\n        // TODO Auto-generated method stub\n        FileSession fs = fileSessions.get(fileBlock.fileSessionID);\n        if (fs != null) {\n            return dwm.offerFileBlock(fileBlock, fs.partitionID(), delay, unit);\n        }\n\n        logger.log(Level.WARNING, \"No such fileSession: \" + fileBlock.fileSessionID + \" in my session map\");\n        return false;\n    }\n\n    public void put(final FileBlock fileBlock) throws InterruptedException {\n        if (isClosed()) {\n            throw new InterruptedException(\"Session is closed\");\n        }\n\n        FileSession fs = fileSessions.get(fileBlock.fileSessionID);\n        if (fs != null) {\n            dwm.putFileBlock(fileBlock, fs.partitionID());\n        } else {\n            logger.log(Level.SEVERE, \"No such fileSession: \" + fileBlock.fileSessionID + \" in my session map\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileBlock.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport java.nio.ByteBuffer;\nimport java.util.UUID;\n\n/**\n * Wrapper class for a simple block ( can be an offset in whatever stream ... not only a file )\n *\n * @author ramiro\n */\npublic class FileBlock {\n\n    //used for signaling between Producers/Consumers\n    //public static final FileBlock EOF_FB = new FileBlock(UUID.randomUUID(), UUID.randomUUID(), -1, ByteBuffer.allocate(0));\n\n    public final UUID fdtSessionID;\n    public final UUID fileSessionID;\n    public final long fileOffset;\n    public final ByteBuffer buff;\n\n    private FileBlock(final UUID fdtSessionID, final UUID fileSessionID, final long fileOffset, final ByteBuffer buff) {\n        if (fdtSessionID == null) {\n            throw new NullPointerException(\" [ FDT Bug ? ] fdtSessionID cannot be null; fileSessionID: \" + fileSessionID);\n        }\n\n        if (fileSessionID == null) {\n            throw new NullPointerException(\" [ FDT Bug ? ] fileSessionID cannot be null; fdtSessionID: \" + fdtSessionID);\n        }\n\n        if (buff == null) {\n            throw new NullPointerException(\" [ FDT Bug ? ] buff cannot be null; fdtSessionID: \" + fdtSessionID + \" fileSessionID: \" + fileSessionID);\n        }\n\n        this.fdtSessionID = fdtSessionID;\n        this.fileSessionID = fileSessionID;\n        this.fileOffset = fileOffset;\n        this.buff = buff;\n    }\n\n    //TODO - Make a simple cache of FileBlock-s objects ... I don't think FDT will gain anything from this \"feature\"\n    // so I will not implement it, yet\n    public static FileBlock getInstance(UUID fdtSessionID, UUID fileSessionID, long fileOffset, ByteBuffer buff) {\n        return new FileBlock(fdtSessionID, fileSessionID, fileOffset, buff);\n    }\n\n    public String toString() {\n        return \"FileBlock for [ \" + fileSessionID + \" ] offset: \" + fileOffset + \" payload: \" + buff;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileBlockConsumer.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * This interface, together with {@link FileBlockProducer} acts as a bridge\n * between the Readers and the Writers in the FDT App\n *\n * @author ramiro\n * @see BlockingQueue\n */\npublic interface FileBlockConsumer {\n\n    public boolean offer(final FileBlock fileBlock, long delay, TimeUnit unit) throws InterruptedException;\n\n    public void put(FileBlock fileBlock) throws InterruptedException;\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileBlockProducer.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * This interface, together with {@link FileBlockConsumer} acts as a bridge\n * between the Readers and the Writers in the FDT App\n *\n * @author ramiro\n * @see BlockingQueue\n */\npublic interface FileBlockProducer {\n\n    public FileBlock take() throws InterruptedException;\n\n    public FileBlock poll();\n\n    public FileBlock poll(long delay, TimeUnit unit) throws InterruptedException;\n\n    public void transportWorkerDown() throws Exception;\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileReaderSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.FileChannelProvider;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.util.UUID;\n\n/**\n * Wrapper class over a current file which is being read\n *\n * @author ramiro\n */\npublic class FileReaderSession extends FileSession {\n\n    public FileReaderSession(String fileName, FDTSession fdtSession, boolean isLoop,\n                             FileChannelProvider fileChannelProvider) throws IOException {\n        this(UUID.randomUUID(), fdtSession, fileName, isLoop, fileChannelProvider);\n    }\n\n    public FileReaderSession(UUID uid, FDTSession fdtSession, String fileName, boolean isLoop,\n                             FileChannelProvider fileChannelProvider) throws IOException {\n        super(uid, fdtSession, fileName, isLoop, fileChannelProvider);\n\n        this.fileName = file.getAbsolutePath();\n        this.file = this.fileChannelProvider.getFile(fileName);\n\n        if (!fileName.startsWith(FileSession.DEV_ZERO_FILENAME) && !file.exists()) {\n            throw new FileNotFoundException(\"No such file: \" + fileName);\n        }\n\n        sessionSize = file.length();\n\n        if (fileName.startsWith(FileSession.DEV_ZERO_FILENAME) || isLoop) {\n            this.sessionSize = -1;\n            return;\n        }\n\n        final boolean bNoChk = Boolean.getBoolean(\"DO_NOT_CHECK_FILE\");\n        if (bNoChk) {\n            this.sessionSize = -1;\n            return;\n        }\n\n        if (!isLoop && !file.isFile()) {\n            throw new IOException(\"The specified name [ \" + fileName + \" ] is not a file!\");\n        }\n\n        this.partitionID = this.fileChannelProvider.getPartitionID(this.file);\n    }\n\n    @Override\n    public String toString() {\n        return \"FileReaderSession [file=\" + file + \", partitionID=\" + partitionID + \", sessionID=\" + sessionID\n                + \", sessionSize=\" + sessionSize + \"]\";\n    }\n\n    @Override\n    public FileChannel getChannel() throws Exception {\n\n        synchronized (closeLock) {\n            if (isClosed()) {\n                if (!isLoop) {\n                    throw new IOException(\"FileReaderSession closed!\");\n                }\n            } else {\n                if (this.fileChannel != null) {\n                    return this.fileChannel;\n                }\n            }\n\n            try {\n                fileChannel = this.fileChannelProvider.getFileChannel(file, null);\n            } catch (Exception ex) {\n                close(\"Cannot instantiate fileChannel\", ex);\n                throw ex;\n            }\n        }\n\n        return fileChannel;\n    }\n\n    // this is always called with closeLock taken !\n    @Override\n    protected void internalClose() {\n        super.internalClose();\n        if (isLoop) {\n            closed = false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.FileChannelProvider;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is the FDT wrapper over the FileChannel which performs the I/O operations\n *\n * @author ramiro\n */\npublic abstract class FileSession extends IOSession {\n\n    public static final String DEV_NULL_FILENAME = \"/dev/null\";\n    public static final String DEV_ZERO_FILENAME = \"/dev/zero\";\n    private static final Logger logger = Logger.getLogger(FileSession.class.getName());\n    public final AtomicLong cProcessedBytes = new AtomicLong(0);\n    protected final boolean isLoop;\n    protected final FDTSession fdtSession;\n    protected final boolean isNull;\n    protected final boolean isZero;\n    protected final FileChannelProvider fileChannelProvider;\n    protected volatile String fileName;\n    protected volatile FileChannel fileChannel;\n    protected volatile File file;\n    protected volatile int partitionID;\n    protected volatile long lastModified;\n\n    public FileSession(UUID uid, FDTSession fdtSession, String fileName, boolean isLoop,\n                       FileChannelProvider fileChannelProvider) {\n        super(uid, -1);\n        this.fdtSession = fdtSession;\n\n        boolean bNull = false;\n        boolean bZero = false;\n        File iFile = null;\n\n        this.fileChannelProvider = fileChannelProvider;\n\n        try {\n            this.isLoop = isLoop;\n\n            //some checks\n            if (fileName == null) {\n                throw new NullPointerException(\"The fileName cannot be null\");\n            }\n\n            iFile = new File(fileName);\n            this.fileName = fileName;\n\n            this.lastModified = iFile.lastModified();\n\n            if (fileName.startsWith(DEV_NULL_FILENAME)) {\n                iFile = new File(DEV_NULL_FILENAME);\n                bNull = true;\n                return;\n            }\n\n            if (fileName.startsWith(DEV_ZERO_FILENAME)) {\n                iFile = new File(DEV_ZERO_FILENAME);\n                bZero = true;\n                return;\n            }\n        } finally {\n            file = iFile;\n            isNull = bNull;\n            isZero = bZero;\n        }\n    }\n\n    public abstract FileChannel getChannel() throws Exception;\n\n    public int partitionID() {\n        return partitionID;\n    }\n\n    public long lastModified() {\n        return lastModified;\n    }\n\n    public final boolean isNull() {\n        return isNull;\n    }\n\n    public final boolean isZero() {\n        return isZero;\n    }\n\n    public File getFile() {\n        return file;\n    }\n\n    public final boolean isLoop() {\n        return isLoop;\n    }\n\n    public void setLastModified(long lastModified) {\n        this.lastModified = lastModified;\n    }\n\n    @Override\n    protected void internalClose() {\n        final FileChannel fileChannel = this.fileChannel;\n        if (fileChannel != null) {\n            try {\n                if (!isLoop) {\n                    fileChannel.close();\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" Got exception closing file \" + file, t);\n            }\n        }\n    }\n\n    public String fileName() {\n        return fileName;\n    }\n\n    /**\n     * @param fileName\n     * @throws IOException\n     */\n    public void setFileName(String fileName) throws IOException {\n        this.fileName = fileName;\n        this.file = new File(fileName);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/FileWriterSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.FileChannelProvider;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.util.UUID;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Wrapper class over a current file which is being written\n *\n * @author ramiro\n */\npublic class FileWriterSession extends FileSession {\n\n    private static final Logger logger = Logger.getLogger(FileSession.class.getName());\n    protected final boolean noLock;\n    protected final boolean noTmp;\n    protected volatile FileLock fLock = null;\n    private volatile boolean channelInitialized;\n    private volatile File tmpCopyFile;\n    private String openMode = \"rw\";\n\n    public FileWriterSession(UUID uid,\n                             FDTSession fdtSession,\n                             String fileName,\n                             long size,\n                             long lastModified,\n                             boolean isLoop,\n                             String writeMode,\n                             boolean noTmp,\n                             boolean noLock,\n                             FileChannelProvider fcp) throws IOException {\n\n        super(uid, fdtSession, fileName, isLoop, fcp);\n        this.noTmp = noTmp;\n\n        this.noLock = noLock;\n        file = fcp.getFile(file.getAbsolutePath());\n        this.sessionSize = size;\n\n        if (!isNull) {\n            this.lastModified = lastModified;\n\n            String tmpF = \"\";\n\n            File parent = file.getParentFile();\n            if (parent != null) {\n                tmpF = parent.getAbsolutePath();\n            }\n\n            // It's not a safe name generator but should be ok\n            // Replace with SecureRandom as per TempDirectory in java.io.File\n            final String fName = tmpF + File.separator + \".\" + Math.random() + file.getName();\n\n            this.tmpCopyFile = fcp.getFile((noTmp) ? file.getAbsolutePath() : fName);\n\n        } else {\n            this.tmpCopyFile = file;\n        }\n\n        try {\n            partitionID = this.fileChannelProvider.getPartitionID(this.tmpCopyFile);\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ FileWriterSession ] cannot determine partition id for: \" + this.tmpCopyFile, t);\n        }\n\n        channelInitialized = false;\n        if (writeMode == null || writeMode.equalsIgnoreCase(\"nosync\")) {\n            openMode = \"rw\";\n        } else if (writeMode.equalsIgnoreCase(\"dsync\")) {\n            openMode = \"rwd\";\n        } else if (writeMode.equalsIgnoreCase(\"sync\")) {\n            openMode = \"rws\";\n        } else {\n            openMode = \"rw\";\n        }\n\n    }\n\n    public static FileWriterSession fromFileWriterSession(FileWriterSession other) throws IOException {\n        return new FileWriterSession(other.sessionID,\n                other.fdtSession,\n                other.fileName,\n                other.sessionSize(),\n                other.lastModified,\n                other.isLoop,\n                other.openMode,\n                other.noTmp,\n                other.noLock,\n                other.fileChannelProvider);\n    }\n\n    @Override\n    public String toString() {\n        return \"FileWriterSession [tmpCopyFile=\" + tmpCopyFile + \", file=\" + file + \", partitionID=\" + partitionID + \", sessionID=\" + sessionID\n                + \", sessionSize=\" + sessionSize + \"]\";\n    }\n\n    public FileChannel getChannel() throws Exception {\n\n        if (channelInitialized) {\n            if (isClosed()) {\n                if (!isLoop) {\n                    throw new Exception(\"Stream closed!\");\n                }\n            } else {\n                return fileChannel;\n            }\n        }\n\n        synchronized (closeLock) {\n\n            if (channelInitialized) {\n                if (isClosed()) {\n                    throw new Exception(\"Stream closed!\");\n                }\n                return fileChannel;\n            }\n\n            if (isClosed()) {\n                throw new Exception(\"Stream closed!\");\n            }\n            try {\n                if (!isNull) {\n                    if (!file.exists()) {\n                        File dirs = fileChannelProvider.getFile(file.getParent());\n\n                        if (!dirs.exists()) {\n                            if (!dirs.mkdirs()) {\n                                throw new IOException(\" Unable to create parent dirs [ \" + dirs + \" ]\");\n                            }\n                        }\n\n                    }\n                }\n\n                try {\n                    partitionID = this.fileChannelProvider.getPartitionID(this.tmpCopyFile);\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" [ FileWriterSession ] cannot determine partition id for: \" + this.tmpCopyFile, t);\n                }\n\n                final FileChannel lfc = this.fileChannelProvider.getFileChannel(tmpCopyFile, openMode);\n\n                if (!noLock && !isNull) {\n                    try {\n                        fLock = lfc.lock();\n                        if (logger.isLoggable(Level.FINE)) {\n                            if (fLock == null) {\n                                logger.log(Level.FINE, \"[ FileWriterSession ] Cannot lock file: \" + tmpCopyFile\n                                        + \"; will try to write without lock taken. No reason given.\");\n                            } else {\n                                logger.log(Level.FINE, \"[ FileWriterSession ] File lock for: \" + tmpCopyFile + \" taken!\");\n                            }\n                        }\n                    } catch (Throwable t) {\n                        fLock = null;\n                        logger.log(Level.WARNING, \"[ FileWriterSession ] Cannot lock file: \" + tmpCopyFile\n                                + \"; will try to write without lock taken. Cause:\", t);\n                    }\n                } else {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \"[ FileWriterSession ] Not using file lock for: \" + tmpCopyFile);\n                    }\n                }\n\n                fileChannel = lfc;\n                channelInitialized = true;\n            } catch (Exception ex) {\n                close(null, ex);\n                throw ex;\n            }\n        }\n\n        return fileChannel;\n    }\n\n    @Override\n    protected void internalClose() {\n        super.internalClose();\n\n        final boolean logFine = logger.isLoggable(Level.FINE);\n        boolean bRename = channelInitialized && !isNull && downCause() == null && file != null && tmpCopyFile != null;\n        try {\n            if (bRename) {\n                if (!tmpCopyFile.equals(file)) {\n                    if (file.exists()) {\n                        if (!file.delete()) {\n                            logger.log(Level.WARNING, \"Unable to delete existing file: \" + file + \". Will try to replace it with: \" + tmpCopyFile);\n                        } else {\n                            if (logFine) {\n                                logger.log(Level.FINE, \"Deleted existing file: \" + file + \". Will replace it with: \" + tmpCopyFile);\n                            }\n                        }\n                    } else {\n                        if (logFine) {\n                            logger.log(Level.FINE, \"No existing file: \" + file + \". Will move temp file: \" + tmpCopyFile + \" to \" + file);\n                        }\n                    }\n                    bRename = tmpCopyFile.renameTo(file);\n                } else {\n                    bRename = true;\n                }\n                if (!file.setLastModified(lastModified)) {\n                    logger.log(Level.WARNING, \"Unable to set modification time for file: \" + file);\n                }\n            } else {\n                bRename = true;\n                if (downCause() != null || downMessage() != null && tmpCopyFile != null) {\n                    if (!isNull) {\n                        if (!tmpCopyFile.delete()) {\n                            if (tmpCopyFile.exists()) {\n                                logger.log(Level.WARNING, \"Unable to delete temporary file: \" + tmpCopyFile);\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (isLoop) {\n                // reset the state\n                channelInitialized = false;\n                closed = false;\n            }\n        } finally {\n            final FileLock fLock = this.fLock;\n            if (fLock != null) {\n                try {\n                    if (fLock.isValid()) {\n                        fLock.release();\n                        if (logFine) {\n                            logger.log(Level.FINE, \"[ FileWriterSession ] Released the lock for file: \" + file);\n                        }\n                    } else {\n                        if (logFine) {\n                            logger.log(Level.FINE, \"[ FileWriterSession ] The lock for file: \" + file + \" no longer valid. File chanel open: \"\n                                    + fileChannel.isOpen());\n                        }\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"[ FileWriterSession ] Unable to release the lock for file: \" + file + \" file channel opened: \"\n                            + fileChannel.isOpen() + \"; Cause: \", t);\n                }\n            } else {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"[ FileWriterSession ] No lock for file: \" + file);\n                }\n            }\n\n            if (!bRename) {\n                final String msg = \"Unable to rename temporary file: [ \" + tmpCopyFile + \" ] to destination file: [ \" + file\n                        + \" ]. Check your file system.\";\n                logger.log(Level.WARNING, msg);\n                if (!isNull & tmpCopyFile != null) {\n                    if (tmpCopyFile.delete()) {\n                        logger.log(Level.INFO, \"Temporary file: \" + tmpCopyFile + \" deleted\");\n                    } else {\n                        logger.log(Level.WARNING, \"Unable to delete temporary file: \" + tmpCopyFile + \" deleted. Check your file system.\");\n                    }\n                }\n\n                // close the file session with errors\n                fdtSession.close(msg, new IOException(msg));\n            }\n        }\n    }\n\n    @Override\n    public void setFileName(String fileName) throws IOException {\n        super.setFileName(fileName);\n        if (!isNull) {\n            this.lastModified = lastModified;\n\n            String tmpF = \"\";\n\n            File parent = file.getParentFile();\n            if (parent != null) {\n                tmpF = parent.getAbsolutePath();\n            }\n\n            // It's not a safe name generator but should be ok\n            // Replace with SecureRandom as per TempDirectory in java.io.File\n            final String fName = tmpF + File.separator + \".\" + Math.random() + file.getName();\n\n            this.tmpCopyFile = this.fileChannelProvider.getFile((noTmp) ? file.getAbsolutePath() : fName);\n\n        } else {\n            this.tmpCopyFile = file;\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/IOSession.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.AbstractFDTCloseable;\n\nimport java.util.UUID;\n\n/**\n * Base class for all sessions inside FDT which are performing I/O.\n *\n * @author ramiro\n */\npublic abstract class IOSession extends AbstractFDTCloseable {\n\n    /**\n     * starting time in millis since Epoch\n     */\n    public final long startTimeMillis;\n    /**\n     * start time in as returned by {@link System#nanoTime()} which usually represents the JVM (or OS) uptime in nanoseconds\n     */\n    public final long startTimeNanos;\n    /**\n     * the one and only session identifier\n     */\n    protected final UUID sessionID;\n    /**\n     * how many bytes should be transferred\n     * As per JLS -- reads and writes will be atomic; as we offer only get()/set() everything should be atomic\n     */\n    protected volatile long sessionSize;\n\n    public IOSession() {\n        this(UUID.randomUUID());\n    }\n\n    /**\n     * @param sessionID UUID representing this session's identifier\n     * @throws NullPointerException if sessionID is null\n     */\n    public IOSession(UUID sessionID) {\n        if (sessionID == null) {\n            throw new NullPointerException(\"Null session ID\");\n        }\n        this.sessionID = sessionID;\n        startTimeMillis = System.currentTimeMillis();\n        startTimeNanos = System.nanoTime();\n    }\n\n    public IOSession(UUID sessionID, long sessionSize) {\n        this(sessionID);\n        this.sessionSize = sessionSize;\n    }\n\n    public UUID sessionID() {\n        return sessionID;\n    }\n\n    public long sessionSize() {\n        return sessionSize;\n    }\n\n    public void setSessionSize(long sessionSize) {\n        this.sessionSize = sessionSize;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/PartitionMap.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.Utils;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Arrays;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Helper class which determines the real partition ID for a file\n *\n * @author Lucian Musat\n * @author ramiro\n */\npublic class PartitionMap {\n\n    public static final String osname = System.getProperty(\"os.name\");\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(PartitionMap.class.getName());\n    private static ConcurrentHashMap<String, Integer> hLocations = new ConcurrentHashMap<String, Integer>();\n\n    public static final int getPartition(String fileName) {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \" OSName in getPartition ( \" + fileName + \" ) is \" + osname);\n        }\n\n        String[] command = null;\n        if (osname.indexOf(\"Linux\") != -1 || osname.indexOf(\"SunOS\") != -1) {\n            // identifies the partition the real file denoted by this path resides on\n            // command=\"/usr/bin/stat -L -c \\\"%d\\\" \\\"\"+fileName+\"\\\"\";\n            command = new String[]{\n                    \"stat\", \"-L\", \"-c\", \"%d\", fileName\n            };\n        } else if (osname.indexOf(\"Win\") != -1) {\n            // not yet implemented!\n        } else if (osname.indexOf(\"Mac\") != -1) {\n            // identifies the major number for the drive that has the file\n            // that means, it identifies the disk, not only the partition\n            // command=\"/usr/bin/stat -L -f \\\"%Hd\\\" \\\"\"+fileName+\"\\\"\";\n            command = new String[]{\n                    \"stat\", \"-L\", \"-f\", \"%Hd\", fileName\n            };\n        }\n        if (command != null) {\n            final String fLine = runICommand(command);\n            if (fLine != null) {\n                try {\n                    return Integer.parseInt(fLine);\n                } catch (Throwable t) {\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \" [ PartitionMap ] exception parsing line: \" + fLine + \" for cmd: \" + Arrays.toString(command));\n                    }\n                }\n            }\n        }\n        return 0;\n    }\n\n    /**\n     * runs a shell command and returns first line if nothing on stderr<br>\n     * TODO: replace with cmdExec.java\n     *\n     * @param cmd\n     * @return\n     * @author mluc\n     * @since Aug 31, 2006\n     */\n    private static String runICommand(final String[] cmd) {\n        BufferedReader br = null;\n        BufferedReader err = null;\n\n        InputStream is = null;\n        InputStream es = null;\n\n        InputStreamReader isr = null;\n        InputStreamReader esr = null;\n\n        try {\n            Process pro = null;\n\n            if (osname.startsWith(\"Linux\") || osname.startsWith(\"Mac\") || osname.startsWith(\"SunOS\")) {\n                pro = Runtime.getRuntime().exec(cmd, new String[]{\n                        \"PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin\"\n                });\n            } else if (osname.startsWith(\"Windows\")) {\n                String exehome = System.getProperty(\"user.home\");\n                pro = Runtime.getRuntime().exec(exehome + cmd);\n            }\n\n            if (pro == null) {\n                return null;\n            }\n\n            is = pro.getInputStream();\n            es = pro.getErrorStream();\n\n            isr = new InputStreamReader(is);\n            esr = new InputStreamReader(es);\n\n            br = new BufferedReader(isr);\n            err = new BufferedReader(esr);\n\n            String line = null;\n            StringBuilder ret = new StringBuilder();\n\n            while ((line = err.readLine()) != null) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \" [ PartitionMap ] [ runICommand ] for cmd: \" + Arrays.toString(cmd) + \" got smth: \" + line\n                            + \" on stderr ... will ignore stdin\");\n                }\n                ret.append(line).append(\"\\n\");\n            }\n\n            if (ret.length() == 0) {\n                final String retLine = br.readLine();\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \" [ PartitionMap ] [ runICommand ] for cmd: \" + Arrays.toString(cmd) + \" read from stdout: \" + retLine);\n                }\n\n                return retLine;\n            }\n\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \" [ PartitionMap ] [ runICommand ] got exception for cmd: \" + Arrays.toString(cmd), t);\n            }\n        } finally {\n            Utils.closeIgnoringExceptions(err);\n            Utils.closeIgnoringExceptions(br);\n            Utils.closeIgnoringExceptions(isr);\n            Utils.closeIgnoringExceptions(esr);\n            Utils.closeIgnoringExceptions(is);\n            Utils.closeIgnoringExceptions(es);\n        }\n\n        return null;\n    }\n\n    /**\n     * stores the directory path to a file and for a second file with the same\n     * directory path will return the last value and will not search for a new one<br>\n     * ATTENTION: if one of two files is a link, then the result returned will probably\n     * not be valid!\n     *\n     * @param fileName\n     * @return tag of partition taken from cache if available\n     * @author mluc\n     * @since Sep 18, 2006\n     */\n    public static int getPartitionFromCache(File file) {\n        String dirPath = \"\";\n        final String fileName = file.getAbsolutePath();\n        boolean isDir = false;\n        if (!file.isDirectory()) {\n            int lastIndex = fileName.lastIndexOf(File.separatorChar);\n            if (lastIndex != -1)\n                dirPath = fileName.substring(0, lastIndex);\n            else\n                dirPath = \"\";\n        } else {\n            isDir = true;\n            dirPath = file.getAbsolutePath();\n        }\n\n        final Integer value = hLocations.get((isDir) ? dirPath : fileName);\n        if (value != null)\n            return value.intValue();\n        int val = getPartition(fileName);\n        hLocations.put(dirPath, Integer.valueOf(val));\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \" [ PartitionMap ] [ getPartitionFromCache ] fileName: \" + fileName + \" partitionID: \" + val);\n        }\n\n        return val;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/PosixFSFileChannelProviderFactory.java",
    "content": "/*\n * Created on Jan 10, 2010\n *\n */\npackage lia.util.net.copy;\n\nimport lia.util.net.common.FileChannelProvider;\nimport lia.util.net.common.FileChannelProviderFactory;\n\nimport java.io.*;\nimport java.nio.channels.FileChannel;\n\n/**\n * @author ramiro\n */\npublic class PosixFSFileChannelProviderFactory implements FileChannelProviderFactory {\n\n    private final FileChannelProvider readerFileChannelProvider;\n    private final FileChannelProvider writerFileChannelProvider;\n    private final FileChannelProvider coordinatorChannelProvider;\n\n\n    public PosixFSFileChannelProviderFactory() {\n        this.readerFileChannelProvider = new PosixFSReaderFileChannelProvider();\n        this.writerFileChannelProvider = new PosixFSWriterFileChannelProvider();\n        this.coordinatorChannelProvider = new PosixFSCoordinatorChannelProvider();\n    }\n\n    /**\n     * @param readerSession\n     */\n    public FileChannelProvider newReaderFileChannelProvider(FDTReaderSession readerSession) {\n        return readerFileChannelProvider;\n    }\n\n    /**\n     * @param writerSession\n     */\n    public FileChannelProvider newWriterFileChannelProvider(FDTWriterSession writerSession) {\n        return writerFileChannelProvider;\n    }\n\n//    /**\n//     * @param coordinatorSession\n//     */\n//    public FileChannelProvider newCoordinatorChannelProvider(FDTCoordinatorSession coordinatorSession) {\n//        return coordinatorChannelProvider;\n//    }\n\n    private static final class PosixFSReaderFileChannelProvider implements FileChannelProvider, Serializable {\n\n        /**\n         * @throws IOException\n         */\n        public File getFile(String fileName) throws IOException {\n            return new File(fileName);\n        }\n\n        /**\n         * @throws IOException\n         */\n        public int getPartitionID(File file) throws IOException {\n            return PartitionMap.getPartitionFromCache(file);\n        }\n\n        /**\n         * @param openMode\n         */\n        @SuppressWarnings(\"resource\")\n        public FileChannel getFileChannel(File file, String openMode) throws IOException {\n            return new FileInputStream(file).getChannel();\n        }\n\n    }\n\n    private static final class PosixFSWriterFileChannelProvider implements FileChannelProvider {\n\n        /**\n         * @throws IOException\n         */\n        public File getFile(String fileName) throws IOException {\n            return new File(fileName);\n        }\n\n        /**\n         * @throws IOException\n         */\n        public int getPartitionID(File file) throws IOException {\n            if (file.exists()) {\n                return PartitionMap.getPartitionFromCache(file);\n            }\n\n            return PartitionMap.getPartitionFromCache(file.getParentFile());\n        }\n\n        @SuppressWarnings(\"resource\")\n        public FileChannel getFileChannel(File file, final String openMode) throws IOException {\n            if (openMode != null) {\n                return new RandomAccessFile(file, openMode).getChannel();\n            }\n\n            return new FileOutputStream(file).getChannel();\n        }\n\n    }\n\n    private static final class PosixFSCoordinatorChannelProvider implements FileChannelProvider {\n\n        /**\n         * @throws IOException\n         */\n        public File getFile(String fileName) throws IOException {\n            return new File(fileName);\n        }\n\n        /**\n         * @throws IOException\n         */\n        public int getPartitionID(File file) throws IOException {\n            if (file.exists()) {\n                return PartitionMap.getPartitionFromCache(file);\n            }\n\n            return PartitionMap.getPartitionFromCache(file.getParentFile());\n        }\n\n        @SuppressWarnings(\"resource\")\n        public FileChannel getFileChannel(File file, final String openMode) throws IOException {\n            if (openMode != null) {\n                return new RandomAccessFile(file, openMode).getChannel();\n            }\n\n            return new FileOutputStream(file).getChannel();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/DiskReaderManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.monitoring.DiskReaderManagerMonitoringTask;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Disk reader Yoda :)\n *\n * @author ramiro\n */\npublic class DiskReaderManager extends GenericDiskManager {\n\n    private static final DiskReaderManager _theInstance = new DiskReaderManager();\n    private DiskReaderManagerMonitoringTask monTask;\n\n    private DiskReaderManager() {\n        monTask = new DiskReaderManagerMonitoringTask(this);\n        Utils.getMonitoringExecService().scheduleWithFixedDelay(monTask, 5, 5, TimeUnit.SECONDS);\n    }\n\n    public static final DiskReaderManager getInstance() {\n        return _theInstance;\n    }\n\n    protected void internalClose() {\n\n    }\n\n    public long getSize() {\n        return -1;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/DiskReaderTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.SystemLoadMonitor;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.FileSession;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.security.MessageDigest;\nimport java.util.List;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class will read the files for a specific partitionID\n * and FDTReaderSession. The tuple ( partitionID, FDTReaderSession ) identifies\n * this task.\n */\npublic class DiskReaderTask extends GenericDiskTask {\n\n    private static final Logger logger = Logger.getLogger(DiskReaderTask.class.getName());\n\n    private static final DiskReaderManager diskReaderManager = DiskReaderManager.getInstance();\n    private final MessageDigest md5Sum;\n    private final boolean computeMD5;\n    private final FDTReaderSession fdtSession;\n    List<FileSession> fileSessions;\n    private AtomicBoolean isFinished = new AtomicBoolean(false);\n    private int addedFBS = 0;\n\n    private static final double HIGH_CORE_LOAD_THRESHOLD = Double.parseDouble(System.getProperty(\"cputh\", \"0.999\")); // 99.9%\n    private static final long HIGH_CONTEXT_SWITCH_THRESHOLD = Long.parseLong(System.getProperty(\"ctxth\", \"100000\"));\n    private static final double HIGH_SYSTEM_LOAD_THRESHOLD = Double.parseDouble(System.getProperty(\"scputh\", \"0.5\"));\n\n    private static final double CPU_LOAD_SCALING_FACTOR = Double.parseDouble(System.getProperty(\"cpuscl\", \"1000.0\"));\n    private static final double CONTEXT_SWITCH_SCALING_FACTOR = Double.parseDouble(System.getProperty(\"ctxscl\", \"0.0001\"));\n\n    private static final long MIN_SLEEP_TIME_NS = 1;   // Minimum sleep time\n    private static final long MAX_SLEEP_TIME_NS = 9999;  // Maximum sleep time\n\n    private static final long SLEEP_EVERY_NS = Long.getLong(\"sleepEvery\", 999999L);\n\n    private static final int NUM_CORES = Runtime.getRuntime().availableProcessors();\n\n    private double previousCpuLoadExcess = 0.0;\n    private double previousContextSwitchExcess = 0.0;\n\n\n    /**\n     * @throws NullPointerException if fdtSession is null or fileSessions list is null\n     **/\n    public DiskReaderTask(final int partitionID, final int taskIndex, final List<FileSession> fileSessions, final FDTReaderSession fdtSession) {\n        super(partitionID, taskIndex);\n        boolean bComputeMD5 = Config.getInstance().computeMD5();\n        MessageDigest md5SumTMP = null;\n\n        if (fdtSession == null) throw new NullPointerException(\"FDTSession cannot be null\");\n        if (fileSessions == null) throw new NullPointerException(\"FileSessions cannot be null\");\n\n        this.fileSessions = fileSessions;\n        this.fdtSession = fdtSession;\n        this.myName = new StringBuilder(\"DiskReaderTask - partitionID: \").append(partitionID).append(\" taskID: \").append(taskIndex).append(\" - [ \").append(fdtSession.toString()).append(\" ]\").toString();\n\n        if (bComputeMD5) {\n            try {\n                md5SumTMP = MessageDigest.getInstance(\"MD5\");\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" \\n\\n\\n Cannot compute MD5. Unable to initiate the MessageDigest engine. Cause: \", t);\n                md5SumTMP = null;\n            }\n        }\n\n        if (md5SumTMP != null) {\n            bComputeMD5 = true;\n        } else {\n            bComputeMD5 = false;\n        }\n\n        md5Sum = md5SumTMP;\n        computeMD5 = bComputeMD5;\n    }\n\n    public void stopIt() {\n        if (isFinished.compareAndSet(false, true)) {\n            //interrupt it if it's blocked in waiting\n            fdtSession.finishReader(partitionID, this);\n        }\n    }\n\n    public void run() {\n\n\n        String cName = Thread.currentThread().getName();\n\n        Thread.currentThread().setName(myName);\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, myName + \" started\");\n        }\n\n        Throwable downCause = null;\n        ByteBuffer buff = null;\n        FileBlock fileBlock = null;\n        long cPosition, readBytes;\n\n        FileSession currentFileSession = null;\n        FileChannel cuurentFileChannel = null;\n        final DirectByteBufferPool bufferPool = DiskReaderTask.bufferPool;\n        final boolean computeMD5 = this.computeMD5;\n        final FDTReaderSession fdtSession = this.fdtSession;\n        if (fdtSession == null) {\n            logger.log(Level.WARNING, \"\\n\\n FDT Session is null in DiskReaderTask !! Will stop reader task\\n\\n\");\n        }\n\n        try {\n            while (!fdtSession.isClosed()) {\n                for (final FileSession fileSession : fileSessions) {\n                    currentFileSession = fileSession;\n\n                    if (fileSession.isClosed()) {\n                        fdtSession.finishFileSession(fileSession.sessionID(), null);\n                        continue;\n                    }\n\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \" [ FileReaderTask ] for FileSession (\" + fileSession.sessionID() + \") \" + fileSession.fileName() + \" started\");\n                    }\n\n                    downCause = null;\n                    long timer = System.currentTimeMillis();\n                    long timer2 = System.currentTimeMillis();\n                    long sleepTimer = System.nanoTime();\n\n                    final FileChannel fileChannel = (fileSession.isZero()) ? null : fileSession.getChannel();\n                    cuurentFileChannel = fileChannel;\n\n                    if (fileChannel != null || fileSession.isZero()) {\n                        if (computeMD5) {\n                            md5Sum.reset();\n                        }\n\n                        cPosition = (fileSession.isZero()) ? 0 : fileChannel.position();\n\n                        for (; ; ) {\n\n                            double[] perCoreLoads = SystemLoadMonitor.getInstance().getPerCoreLoads();\n                            double maxCoreLoad = 0.0;\n                            for (double coreLoad : perCoreLoads) {\n                                if (coreLoad > maxCoreLoad) {\n                                    maxCoreLoad = coreLoad;\n                                }\n                            }\n\n                            long currentContextSwitches = SystemLoadMonitor.getInstance().getContextSwitches();\n                            double[] systemLoadAverages = SystemLoadMonitor.getInstance().getSystemLoadAverage();\n                            double systemLoad1Min = systemLoadAverages[0]; // 1-minute load average\n\n                            double cpuLoadExcess = maxCoreLoad - HIGH_CORE_LOAD_THRESHOLD;\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                logger.log(Level.FINE, \"Max core load: \" + maxCoreLoad + \" exces: \" + cpuLoadExcess);\n                            }\n                            cpuLoadExcess = Math.max(cpuLoadExcess, 0);\n\n                            double normalizedSystemLoad = systemLoad1Min / NUM_CORES;\n                            double systemLoadExcess = normalizedSystemLoad - HIGH_SYSTEM_LOAD_THRESHOLD;\n                            systemLoadExcess = Math.max(systemLoadExcess, 0);\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                logger.log(Level.FINE, \"Max system load: \" + normalizedSystemLoad + \" exces: \" + systemLoadExcess);\n                            }\n\n                            long contextSwitchExcess = currentContextSwitches - HIGH_CONTEXT_SWITCH_THRESHOLD;\n                            contextSwitchExcess = Math.max(contextSwitchExcess, 0);\n\n                            double alpha = 0.2; // Smoothing factor between 0 and 1\n\n                            cpuLoadExcess = previousCpuLoadExcess * (1 - alpha) + cpuLoadExcess * alpha;\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                logger.log(Level.FINE, \"CPU excess : \" + cpuLoadExcess);\n                            }\n                            previousCpuLoadExcess = cpuLoadExcess;\n\n                            contextSwitchExcess = (long) (previousContextSwitchExcess * (1 - alpha) + contextSwitchExcess * alpha);\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                logger.log(Level.FINE, \"Context switches excess : \" + contextSwitchExcess);\n                            }\n                            previousContextSwitchExcess = contextSwitchExcess;\n\n                            double cpuSleepTime = cpuLoadExcess * CPU_LOAD_SCALING_FACTOR; // In milliseconds\n                            double contextSwitchSleepTime = contextSwitchExcess * CONTEXT_SWITCH_SCALING_FACTOR; // In milliseconds\n                            double systemLoadSleepTime = systemLoadExcess * CPU_LOAD_SCALING_FACTOR; // In milliseconds\n\n                            double totalSleepTime = cpuSleepTime + contextSwitchSleepTime + systemLoadSleepTime;\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                timer2 = System.currentTimeMillis();\n                                logger.log(Level.FINE, \"Total sleep time: \" + totalSleepTime + \" CPU : \" + cpuSleepTime + \" context \" + contextSwitchSleepTime + \" system load \" + systemLoadSleepTime);\n                            }\n                            totalSleepTime = Math.max(totalSleepTime, MIN_SLEEP_TIME_NS);\n                            totalSleepTime = Math.min(totalSleepTime, MAX_SLEEP_TIME_NS);\n\n                            int sleepTimeNanos = (int) Math.max(totalSleepTime, 0);\n                            if((System.currentTimeMillis() - timer2) > 10000) {\n                                timer2 = System.currentTimeMillis();\n                                logger.log(Level.FINE, \"Total sleep time: \" + sleepTimeNanos);\n                            }\n\n                            if (cpuLoadExcess > 0 || contextSwitchExcess > 0 || systemLoadExcess > 0) {\n                                if (totalSleepTime > 1) {\n                                    try {\n                                        if(Config.getInstance().isThrottlingEnabled()) {\n                                            if((System.currentTimeMillis() - timer) > 10000)\n                                            {\n                                                timer = System.currentTimeMillis();\n                                                logger.info(\"Throttling data transfer due to high system load. CPU Load: \"+ String.format(\"%f\", cpuLoadExcess) +\", Context Switches: \"+ contextSwitchExcess + \" Throttling with dynamic sleep: \" + totalSleepTime);\n                                                //logger.log(Level.INFO, \"Start throttling due \" + cpuLoadExcess + \" or contexts:\" + contextSwitchExcess);\n                                                //logger.info(\"Throttling with dynamic sleep: \" + totalSleepTime);\n                                            }\n                                            if((System.nanoTime() - sleepTimer) > SLEEP_EVERY_NS)\n                                            {\n                                                sleepTimer = System.currentTimeMillis();\n                                                Thread.sleep(0, sleepTimeNanos);\n                                            }\n\n                                        }\n                                    } catch (InterruptedException e) {\n                                        Thread.currentThread().interrupt();\n                                        break;\n                                    }\n                                }\n                            }\n\n                            //try to get a new buffer from the pool\n                            buff = null;\n                            fileBlock = null;\n\n                            while (buff == null) {\n                                if (fdtSession.isClosed()) {\n                                    return;\n                                }\n                                buff = bufferPool.poll(2, TimeUnit.SECONDS);\n                            }\n\n                            if (fileSession.isZero()) {\n                                //Just play with the buffer markers ... do not even touch /dev/zero\n                                readBytes = buff.capacity();\n                                buff.position(0);\n                                buff.limit(buff.capacity());\n                            } else {\n                                readBytes = fileChannel.read(buff);\n                                if (logger.isLoggable(Level.FINEST)) {\n                                    StringBuilder sb = new StringBuilder(1024);\n                                    sb.append(\" [ DiskReaderTask ] FileReaderSession \").append(fileSession.sessionID()).append(\": \").append(fileSession.fileName());\n                                    sb.append(\" fdtSession: \").append(fdtSession.sessionID()).append(\" read: \").append(readBytes);\n                                    logger.log(Level.FINEST, sb.toString());\n                                }\n                            }\n\n                            if (readBytes == -1) {//EOF\n                                if (fileSession.cProcessedBytes.get() == fileSession.sessionSize()) {\n                                    fdtSession.finishFileSession(fileSession.sessionID(), null);\n                                } else {\n                                    if (!fdtSession.loop()) {\n                                        StringBuilder sbEx = new StringBuilder();\n                                        sbEx.append(\"FileSession: ( \").append(fileSession.sessionID()).append(\" ): \").append(fileSession.fileName());\n                                        sbEx.append(\" total length: \").append(fileSession.sessionSize()).append(\" != total read until EOF: \").append(fileSession.cProcessedBytes.get());\n                                        fdtSession.finishFileSession(fileSession.sessionID(), new IOException(sbEx.toString()));\n                                    } else {\n                                        fileChannel.position(0);\n                                    }\n                                }\n                                bufferPool.put(buff);\n                                buff = null;\n                                fileBlock = null;\n                                if (computeMD5) {\n                                    byte[] md5ByteArray = md5Sum.digest();\n                                    if (logger.isLoggable(Level.FINEST)) {\n                                        logger.log(Level.FINEST, Utils.md5ToString(md5ByteArray) + \"   --->  \" + fileSession.fileName()\n                                        );\n                                    }\n                                    fdtSession.setMD5Sum(fileSession.sessionID(), md5ByteArray);\n                                }\n                                break;\n                            }\n\n                            if (computeMD5) {\n                                buff.flip();\n                                md5Sum.update(buff);\n                            }\n\n                            fileSession.cProcessedBytes.addAndGet(readBytes);\n                            diskReaderManager.addAndGetTotalBytes(readBytes);\n                            diskReaderManager.addAndGetUtilBytes(readBytes);\n                            addAndGetTotalBytes(readBytes);\n                            addAndGetUtilBytes(readBytes);\n\n                            fdtSession.addAndGetTotalBytes(readBytes);\n                            fdtSession.addAndGetUtilBytes(readBytes);\n\n                            if (!fileSession.isZero()) {\n                                buff.flip();\n                            }\n\n                            fileBlock = FileBlock.getInstance(fdtSession.sessionID(), fileSession.sessionID(), cPosition, buff);\n                            cPosition += readBytes;\n\n                            if (!fdtSession.isClosed()) {\n                                while (!fdtSession.fileBlockQueue.offer(fileBlock, 2, TimeUnit.SECONDS)) {\n                                    if (fdtSession.isClosed()) {\n                                        return;\n                                    }\n                                }\n                                fileBlock = null;\n                                buff = null;\n                                addedFBS++;\n                            } else {\n                                try {\n                                    if (fileBlock != null && fileBlock.buff != null) {\n                                        bufferPool.put(fileBlock.buff);\n                                        buff = null;\n                                        fileBlock = null;\n                                    }\n                                    return;\n                                } catch (Throwable t1) {\n                                    if (logger.isLoggable(Level.FINER)) {\n                                        logger.log(Level.FINER, \" Got exception returning bufer to the buffer pool\", t1);\n                                    }\n                                }\n                            }\n\n                            fileBlock = null;\n                        }//while()\n\n                    } else {\n                        if (logger.isLoggable(Level.FINER)) {\n                            logger.log(Level.FINER, \" Null file channel for fileSession\" + fileSession);\n                        }\n                        downCause = new NullPointerException(\"Null File Channel inside reader worker\");\n                        downCause.fillInStackTrace();\n                        fdtSession.finishFileSession(fileSession.sessionID(), downCause);\n                    }\n\n                }//for - fileSession\n\n                if (!fdtSession.loop()) {\n                    break;\n                }\n            }//for\n\n        } catch (IOException ioe) {\n            //check for down\n            if (isFinished.get() || fdtSession.isClosed()) {//most likely a normal error\n                logger.log(Level.FINEST, \" [ HANDLED ] Got I/O Exception reading FileSession (\" + currentFileSession.sessionID() + \") \" + currentFileSession.fileName(), ioe);\n                return;\n            }\n\n            if (!isFinished.getAndSet(true) && !fdtSession.isClosed()) {//most likely a normal error\n                logger.log(Level.INFO, \" [ HANDLED ] Got I/O Exception reading FileSession (\" + currentFileSession.sessionID() + \") / \" + currentFileSession.fileName(), ioe);\n                downCause = ioe;\n                fdtSession.finishFileSession(currentFileSession.sessionID(), downCause);\n                return;\n            }\n\n            downCause = ioe;\n            fdtSession.finishFileSession(currentFileSession.sessionID(), downCause);\n\n        } catch (Throwable t) {\n            if (isFinished.get() || fdtSession.isClosed()) {//most likely a normal error\n                logger.log(Level.FINEST, \"Got General Exception reading FileSession (\" + currentFileSession.sessionID() + \") \" + currentFileSession.fileName(), t);\n                return;\n            }\n\n            downCause = t;\n            fdtSession.finishFileSession(currentFileSession.sessionID(), downCause);\n        } finally {\n\n            if (logger.isLoggable(Level.FINE)) {\n                final StringBuilder logMsg = new StringBuilder(\"DiskReaderTask - partitionID: \").append(partitionID).append(\" taskID: \").append(this.taskID);\n                if (downCause == null) {\n                    logMsg.append(\" Normal exit fdtSession.isClosed() = \").append(fdtSession.isClosed());\n                } else {\n                    logMsg.append(\" Exit with error: \").append(Utils.getStackTrace(downCause)).append(\"fdtSession.isClosed() = \").append(fdtSession.isClosed());\n                }\n                logger.log(Level.FINE, logMsg.toString());\n            }\n\n            if (cuurentFileChannel != null) {\n                try {\n                    cuurentFileChannel.close();\n                } catch (Throwable ignore) {\n                }\n            }\n\n            try {\n                if (buff != null) {\n                    bufferPool.put(buff);\n                    try {\n                        if (fileBlock != null && fileBlock.buff != null && fileBlock.buff != buff) {\n                            boolean bPut = bufferPool.put(fileBlock.buff);\n                            if (logger.isLoggable(Level.FINEST)) {\n                                logger.log(Level.FINEST, \" [ FINALLY ] DiskReaderTask RETURNING FB buff: \" + fileBlock.buff + \" to pool [ \" + bPut + \" ]\");\n                            }\n                        }\n                    } catch (Throwable t1) {\n                        if (logger.isLoggable(Level.FINER)) {\n                            logger.log(Level.FINER, \" Got exception returning bufer to the buffer pool\", t1);\n                        }\n                    }\n                    buff = null;\n                    fileBlock = null;\n                }\n            } catch (Throwable t1) {\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \" Got exception returning bufer to the buffer pool\", t1);\n                }\n            }\n\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \"\\n\\n \" + myName + \" finishes. \" +\n                        \"\\n fdtSession is \" + ((fdtSession.isClosed()) ? \"closed\" : \"open\") + \"\" +\n                        \" Processed FBS = \" + addedFBS + \" \\n\\n\");\n            }\n\n            Thread.currentThread().setName(cName);\n        }\n\n    }//run()\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/DiskWriterManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.monitoring.DiskWriterManagerMonitoringTask;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.*;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The master of all the disk writer threads\n *\n * @author ramiro\n */\npublic class DiskWriterManager extends GenericDiskManager {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(DiskWriterManager.class.getName());\n\n    private static final Config config = Config.getInstance();\n    private static int MAX_PARTITION_COUNT = Integer.getInteger(\"fdt.MAX_PARTITION_COUNT\", 1000).intValue();\n\n    private static int WRITER_QUEUE_MULTIPLY_FACTOR = Integer.getInteger(\"fdt.wQueueM\", 20).intValue();\n    private static DiskWriterManager _thisInstance;\n    private static volatile boolean initialized = false;\n    private final ExecutorService execService;\n    protected Exception finishException = null;\n    /**\n     * The map of DiskWriterTask-s per partition. The key is the partitionID.\n     */\n    ConcurrentHashMap<Integer, List<DiskWriterTask>> diskWritersMap = new ConcurrentHashMap<Integer, List<DiskWriterTask>>();\n    /**\n     * The map of the Queues for every partitionID\n     */\n    ConcurrentHashMap<Integer, BlockingQueue<FileBlock>> diskQueuesMap = new ConcurrentHashMap<Integer, BlockingQueue<FileBlock>>();\n    private int writersPerPartionCount = 1;\n\n    private DiskWriterManager() {\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \" \\n\\n --------> DiskWriterManager is instantiating <--------------- \\n\\n\");\n        }\n\n        //MAX Number of partitions in the system\n        MAX_PARTITION_COUNT = config.getMaxPartitionCount();\n\n        //how many writers per partition\n        writersPerPartionCount = config.getWritersCount();\n\n        if (writersPerPartionCount < 0) {\n            writersPerPartionCount = 1;\n        }\n\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \"DiskWriterManager will use: \" + writersPerPartionCount + \" writers per partition\");\n        }\n\n        //TODO - is there a way to get the number of all partitions in a system ??\n        execService = Utils.getStandardExecService(\"DiskWriterTask \", 1, MAX_PARTITION_COUNT * writersPerPartionCount,\n                Thread.NORM_PRIORITY);\n\n        //Monitoring & Nice Prnting\n        ScheduledExecutorService monitoringService = Utils.getMonitoringExecService();\n        monitoringService.scheduleWithFixedDelay(new DiskWriterManagerMonitoringTask(this), 1, 5, TimeUnit.SECONDS);\n\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \" \\n\\n --------> DiskWriterManager is instantiatied <--------------- \\n\\n\");\n        }\n    }\n\n    public static final DiskWriterManager getInstance() {\n        if (!initialized) {\n            synchronized (DiskWriterManager.class) {\n                if (!initialized) {\n                    _thisInstance = new DiskWriterManager();\n                    initialized = true;\n                }\n            }\n        }\n\n        return _thisInstance;\n    }\n\n    @Override\n    protected void internalClose() {\n        for (Integer parititonID : diskWritersMap.keySet()) {\n            stopWritersForPartition(parititonID);\n        }\n    }\n\n    public Map<Integer, List<DiskWriterTask>> getWritersMap() {\n        return diskWritersMap;\n    }\n\n    synchronized void stopWritersForPartition(Integer partitionID) {\n        final List<DiskWriterTask> writersTasks = diskWritersMap.remove(partitionID);\n        if (writersTasks != null) {\n            for (DiskWriterTask dwt : writersTasks) {\n                if (dwt != null) {\n                    dwt.stopIt();\n                }\n                return;\n            }\n        }\n\n        diskQueuesMap.remove(partitionID);\n\n        logger.log(Level.INFO, \" All the writers for partitionID: \" + partitionID + \" were stopped!\");\n    }\n\n    private synchronized boolean startWritersForPartition(int partitionID) {\n        final Integer iPart = Integer.valueOf(partitionID);\n        BlockingQueue<FileBlock> pQueue = diskQueuesMap.get(iPart);\n        if (pQueue != null) {\n            return false;\n        }\n\n        pQueue = new ArrayBlockingQueue<FileBlock>(WRITER_QUEUE_MULTIPLY_FACTOR * writersPerPartionCount);\n\n        if (diskQueuesMap.putIfAbsent(iPart, pQueue) == null) {\n            //We should start the writers for this partition\n\n            ArrayList<DiskWriterTask> diskWritersTasks = new ArrayList<DiskWriterTask>(writersPerPartionCount);\n\n            for (int i = 0; i < writersPerPartionCount; i++) {\n                //TODO - take it out as a param\n                DiskWriterTask dwt = new DiskWriterTask(partitionID, i, pQueue);\n                diskWritersTasks.add(dwt);\n                //first block for this writer\n                execService.submit(dwt);\n            }\n\n            if (diskWritersTasks.size() <= 0) {\n                logger.log(Level.SEVERE, \"\\n\\n [ BUG ?] diskWritersTasks has size 0 in startWritersForPartition(\"\n                        + partitionID + \")...\\n\\n\");\n                return false;\n            }\n\n            diskWritersMap.put(iPart, diskWritersTasks);\n            return true;\n        }\n\n        return false;\n    }\n\n    public int getQueueSize(int partitionID) {\n        final BlockingQueue<FileBlock> pQueue = diskQueuesMap.get(Integer.valueOf(partitionID));\n\n        if (pQueue == null) {\n            return -1;\n        }\n\n        return pQueue.size();\n    }\n\n    public boolean offerFileBlock(FileBlock fileBlock, int partitionID, long timeout, TimeUnit unit)\n            throws InterruptedException {\n        final Integer iPart = Integer.valueOf(partitionID);\n        BlockingQueue<FileBlock> pQueue = diskQueuesMap.get(iPart);\n        if (pQueue != null) {\n            return pQueue.offer(fileBlock, timeout, unit);\n        }\n\n        startWritersForPartition(partitionID);\n\n        //Do not loose the fileBlock if cannot start\n        pQueue = diskQueuesMap.get(iPart);\n        if (pQueue != null) {\n            return pQueue.offer(fileBlock, timeout, unit);\n        }\n\n        logger.log(Level.SEVERE,\n                \" [ FDT BUG ] Please notify developers! In DiskWriterManager pQueue is null after startWritersForPartition(\"\n                        + partitionID + \") was called! Synch problems?\");\n\n        //we should never get here\n        return false;\n    }\n\n    public void putFileBlock(FileBlock fileBlock, int partitionID) throws InterruptedException {\n        final Integer iPart = Integer.valueOf(partitionID);\n\n        BlockingQueue<FileBlock> pQueue = diskQueuesMap.get(iPart);\n        if (pQueue != null) {\n            pQueue.put(fileBlock);\n            return;\n        }\n\n        startWritersForPartition(partitionID);\n\n        pQueue = diskQueuesMap.get(iPart);\n        if (pQueue != null) {\n            pQueue.put(fileBlock);\n        } else {\n            logger.log(Level.SEVERE,\n                    \" [ FDT BUG ] Please notify developers! In DiskWriterManager pQueue is null after startWritersForPartition(\"\n                            + partitionID + \") was called! Synch problems?\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/DiskWriterTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.FDTSessionManager;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.FileSession;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * per partition DiskWriterTask .... ( there may be more than one writer per\n * partition )\n *\n * @author ramiro\n */\npublic class DiskWriterTask extends GenericDiskTask {\n\n    private static final Logger logger = Logger.getLogger(DiskWriterTask.class.getName());\n\n    private static final DiskWriterManager dwm = DiskWriterManager.getInstance();\n\n    private static final FDTSessionManager fsm = FDTSessionManager.getInstance();\n    final BlockingQueue<FileBlock> queue;\n    private final Lock countersRLock;\n    private final Lock countersWLock;\n    private final AtomicBoolean hasToRun;\n    private final boolean doNotForceOnClose;\n    public long dtTake;\n    public long dtWrite;\n    public long dtFinishSession;\n    public long dtTotal;\n    long sTime;\n    long sTimeWrite;\n    long sTimeFinish;\n    long finishTime;\n\n    DiskWriterTask(int partitionID, int writerID, BlockingQueue<FileBlock> queue) {\n        super(partitionID, writerID);\n        this.queue = queue;\n        hasToRun = new AtomicBoolean(true);\n        final ReadWriteLock rwl = new ReentrantReadWriteLock();\n        countersRLock = rwl.readLock();\n        countersWLock = rwl.writeLock();\n        final boolean hasP = (System.getProperty(\"fdt.doNotForceOnClose\") != null);\n        doNotForceOnClose = (hasP) ? Boolean.getBoolean(\"fdt.doNotForceOnClose\") : true;\n    }\n\n    public void stopIt() {\n\n        if (hasToRun.compareAndSet(true, false)) {\n            logger.log(Level.INFO, this.myName + \" STOPPED!\");\n\n        }\n\n    }\n\n    public final Lock getCountersRLock() {\n        return countersRLock;\n    }\n\n    public int partitionID() {\n        return partitionID;\n    }\n\n    public BlockingQueue<FileBlock> queue() {\n        return queue;\n    }\n\n    public final int writerID() {\n        return taskID;\n    }\n\n    @Override\n    public void run() {\n\n        final String cName = Thread.currentThread().getName();\n        this.myName = new StringBuilder(\"DiskWriterTask [ partitionID=\").append(this.partitionID)\n                .append(\", writerID= \").append(this.taskID).append(\", tid=\").append(Thread.currentThread().getId())\n                .append(\" ] since: \").append(new java.util.Date()).toString();\n\n        try {\n            Thread.currentThread().setName(myName);\n        } catch (Throwable t1) {\n            logger.log(Level.SEVERE, \"Got exception trying to set thread name for DiskWriterTask\", t1);\n        }\n\n        int writtenBytes = -1;\n\n        final BlockingQueue<FileBlock> queue = this.queue;\n\n        logger.log(Level.INFO, myName + \" STARTED. Active = \" + hasToRun.get());\n\n        while (hasToRun.get()) {\n\n            FileBlock fileBlock = null;\n            FileChannel fileChannel = null;\n            FileSession fileSession = null;\n            FDTSession fdtSession = null;\n\n            try {\n                sTime = System.nanoTime();\n                sTimeFinish = 0;\n\n                fileBlock = queue.poll(10, TimeUnit.SECONDS);\n\n                if ((fileBlock == null) || (fileBlock.buff == null)) {// Timeout\n                    if (hasToRun.get()) {\n                        continue;\n                    }\n\n                    break;\n                }\n\n                fdtSession = fsm.getSession(fileBlock.fdtSessionID);\n\n                if (fdtSession == null) {// way to fast ...\n                    logger.log(Level.WARNING, myName + \" Got a fileBlock for fdtSessionID: \" + fileBlock.fdtSessionID\n                            + \" but the session does not appear to be in the manager's map\");\n                    continue;\n                }\n\n                fileSession = fdtSession.getFileSession(fileBlock.fileSessionID);\n\n                if (fileSession == null) {\n                    logger.log(Level.WARNING, \" No such fileSession in local map [ fileSessionID: \"\n                            + fileBlock.fileSessionID + \", fdtSessionID: \" + fileBlock.fdtSessionID + \" ]\");\n                    continue;\n                }\n\n                sTimeWrite = System.nanoTime();\n\n                fileChannel = fileSession.getChannel();\n                if (fileChannel != null) {\n                    writtenBytes = -1;\n\n                    final int remainingBeforeWrite = fileBlock.buff.remaining();\n\n                    if (!fileSession.isLoop()) {\n                        if (fileBlock.buff.remaining() % 4096 != 0) {\n                            // This relies on the allocated buffers capacities to be aligned to 4K as well\n                            // Should be guaranteed by the specification of block size (default 16K, normally way larger)\n                            int toTruncate = fileBlock.buff.remaining();\n                            int toExtend = (toTruncate + 4096) & ~(4096 - 1);\n                            fileBlock.buff.limit(toExtend);\n                            int added = toExtend - toTruncate;\n                            writtenBytes = fileChannel.write(fileBlock.buff, fileBlock.fileOffset) - added;\n                            fileChannel.truncate(fileBlock.fileOffset + toTruncate); // Truncate to get rid of excess\n                        } else {\n                            writtenBytes = fileChannel.write(fileBlock.buff, fileBlock.fileOffset);\n                        }\n                    } else {\n                        writtenBytes = fileChannel.write(fileBlock.buff);\n                    }\n\n                    // if(fileSession.shouldFlush()) {\n                    // fileChannel.force(false);\n                    // }\n\n                    // TODO - Is this even possible? If yes ??!? ... is it\n                    // something going wrong with Kernel/FS???\n                    // In fact it was possible ... @ Caltech with cithep212 (\n                    // RHEL/kernel issue )\n                    if (fileBlock.buff.hasRemaining()) {\n                        final File f = fileSession.getFile();\n                        long freeSpace = -1;\n                        long totalSpace = -1;\n                        long usableSpace = -1;\n                        final File fp = ((f != null) && f.exists()) ? f : f.getParentFile();\n\n                        if (fp != null) {\n                            freeSpace = fp.getFreeSpace();\n                            totalSpace = fp.getTotalSpace();\n                            usableSpace = fp.getUsableSpace();\n                        }\n\n                        String ratio = \"\";\n                        boolean isFull = false;\n                        if (totalSpace > 0L) {\n                            final double freeSpaceRatio = freeSpace / totalSpace;\n                            final double usableSpaceRatio = usableSpace / totalSpace;\n                            ratio += \"freeSpaceRatio: \" + Utils.percentDecimalFormat(freeSpaceRatio)\n                                    + \"% usableSpaceRatio: \" + Utils.percentDecimalFormat(usableSpaceRatio) + \"%\";\n                            if ((freeSpace < fileBlock.buff.capacity()) || (usableSpace < fileBlock.buff.capacity())\n                                    || (freeSpaceRatio < 5d) || (usableSpaceRatio < 5d)) {\n                                isFull = true;\n                                ratio += \"\\n\\n Not enough space to write the buffers on current partition!\";\n                            }\n                        } else {\n                            ratio += \" totalSpace: \" + totalSpace\n                                    + \" <= 0 BYTES; free/usable ratio cannot be computed !\";\n                        }\n\n                        String cause = \"\";\n                        if (!isFull) {\n                            cause = \"\\n\\n\\n [ ERROR ] \"\n                                    + myName\n                                    + \" buffer still hasRemaining() for file: \"\n                                    + f\n                                    + \"\\n\"\n                                    + \"\\n The disk partition may be full or there is a BUG in FileSystem/Kernel/OS/Java NIO !! \\n\"\n                                    + \"\\n\\n Disk partition statistics for \"\n                                    + fp\n                                    + \":\\n\"\n                                    + \"\\n Total free/usable/total space: \"\n                                    + freeSpace\n                                    + \" / \"\n                                    + usableSpace\n                                    + \" / \"\n                                    + totalSpace\n                                    + \" bytes\"\n                                    + \"\\n \"\n                                    + ratio\n                                    + \"\\n\\n\"\n                                    + \"\\n Please note that the partial file will be deleted and space may be available after the session finishes! \\n\\n\"\n                                    + \"\\n fileblock offset = \" + fileBlock.fileOffset\n                                    + \"\\n buff.remaining() before write: \" + remainingBeforeWrite\n                                    + \"\\n buff.remaining() after write: \" + fileBlock.buff.remaining()\n                                    + \"\\n new position = \" + fileChannel.position() + \"\\n written bytes = \"\n                                    + writtenBytes + \"\\n\\n\\n\";\n                        } else {\n                            cause = \"\\n\\n\\n [ ERROR ] \"\n                                    + myName\n                                    + \"\\n The disk partition for: \"\n                                    + fp\n                                    + \" may be full \\n\"\n                                    + \"\\n Total free/usable/total space: \"\n                                    + freeSpace\n                                    + \" / \"\n                                    + usableSpace\n                                    + \" / \"\n                                    + totalSpace\n                                    + \" bytes\"\n                                    + \"\\n \"\n                                    + ratio\n                                    + \"\\n\\n\"\n                                    + \"\\n Please note that the partial file will be deleted and space may be available after the session finishes! \\n\\n\";\n                        }\n\n                        fdtSession.close(cause, new IOException(cause));\n                        continue;\n                    }\n\n                    if (writtenBytes == -1) {\n                        sTimeFinish = System.nanoTime();\n                        logger.log(Level.WARNING, \"\\n\\n [ ERROR ] \" + myName + \" ... Unable to write bytes to [  ( \"\n                                + fileSession.sessionID() + \" ): \" + fileSession.fileName()\n                                + \" ] Disk full or R/O partition ?\");\n                        Throwable downCause = new IOException(\n                                \"Unable to write bytes ????  [ Full disk or R/O partition ]\");\n                        downCause.fillInStackTrace();\n                        fsm.getSession(fileBlock.fdtSessionID).finishFileSession(fileSession.sessionID(), downCause);\n                    } else {\n                        fileSession.cProcessedBytes.addAndGet(writtenBytes);\n\n                        dwm.addAndGetTotalBytes(writtenBytes);\n                        dwm.addAndGetUtilBytes(writtenBytes);\n\n                        addAndGetTotalBytes(writtenBytes);\n                        addAndGetUtilBytes(writtenBytes);\n\n                        fdtSession.addAndGetTotalBytes(writtenBytes);\n                        fdtSession.addAndGetUtilBytes(writtenBytes);\n\n                    }\n\n                    // forcing file channel close() - hadoop issues\n                    if (fileSession.cProcessedBytes.get() == fileSession.sessionSize()) {// EOF\n                        if (!fdtSession.loop()) {\n                            try {\n                                if (!fileSession.isNull() && !fileSession.isZero()) {\n                                    if (doNotForceOnClose) {\n                                        if (logger.isLoggable(Level.FINER)) {\n                                            logger.log(Level.FINER,\n                                                    \"CLOSE - Not enforcing flush - \" + fileSession.getFile()\n                                                            + \" closing without forcing the channel\");\n                                        }\n                                    } else {\n                                        fileSession.getChannel().force(true);\n                                    }\n                                }\n                            } catch (Throwable t1) {\n                                logger.log(Level.WARNING, myName\n                                        + \" got exception forcing data to  writer channel for file writer session \"\n                                        + fileSession, t1);\n                            }\n\n                            // let this one throw an exception\n                            fileSession.getChannel().close();\n                        }\n\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \"\\n \" + myName + \" ... All the bytes ( \" + fileSession.sessionSize()\n                                    + \" ) for [  ( \" + fileSession.sessionID() + \" ): \" + fileSession.fileName()\n                                    + \" ] have been written \");\n                        }\n\n                        if (!fdtSession.loop()) {\n                            fdtSession.finishFileSession(fileSession.sessionID(), null);\n                        }\n\n                        fileSession.close(null, null);\n\n                        sTimeFinish = System.nanoTime();\n\n                    }\n\n                } else {\n                    Throwable downCause = new NullPointerException(\"Null File Channel inside disk writer worker [ \"\n                            + myName + \" ] for [  ( \" + fileSession.sessionID() + \" ): \" + fileSession.fileName()\n                            + \" ]\");\n                    downCause.fillInStackTrace();\n                    sTimeFinish = System.nanoTime();\n                    fsm.getSession(fileBlock.fdtSessionID).finishFileSession(fileSession.sessionID(), downCause);\n                }\n\n                finishTime = System.nanoTime();\n\n                countersWLock.lock();\n                try {\n                    dtTotal += (finishTime - sTime);\n                    dtTake += (sTimeWrite - sTime);\n                    if (sTimeFinish != 0) {\n                        dtWrite += (sTimeFinish - sTimeWrite);\n                        dtFinishSession += (finishTime - sTimeFinish);\n                    } else {\n                        dtWrite += (finishTime - sTimeWrite);\n                    }\n                } finally {\n                    countersWLock.unlock();\n                }\n\n            } catch (IOException ioe) {\n                sTimeFinish = System.nanoTime();\n                logger.log(Level.SEVERE,\n                        myName + \" ... Got I/O Exception writing to file [  ( \" + fileSession.sessionID() + \" ): \"\n                                + fileSession.fileName() + \" ] offset: \" + fileBlock.fileOffset, ioe);\n                if (fileSession.sessionID() != null) {\n                    fdtSession.finishFileSession(fileSession.sessionID(), ioe);\n                }\n            } catch (InterruptedException ie) {\n                if (fileSession == null) {\n                    logger.log(\n                            Level.SEVERE,\n                            myName\n                                    + \" ... Got InterruptedException Exception writing to file [  ( fileSession is null ) ] offset: \"\n                                    + ((fileBlock == null) ? \" fileBlock is null\" : \"\" + fileBlock.fileOffset), ie);\n                } else {\n                    logger.log(Level.SEVERE, myName + \" ... Got InterruptedException Exception writing to file [  ( \"\n                            + fileSession.sessionID() + \" ): \" + fileSession.fileName() + \" ] offset: \"\n                            + ((fileBlock == null) ? \" fileBlock is null\" : \"\" + fileBlock.fileOffset), ie);\n                }\n            } catch (Throwable t) {\n                sTimeFinish = System.nanoTime();\n                if (fileSession == null) {\n                    logger.log(\n                            Level.SEVERE,\n                            myName\n                                    + \" ... Got GeneralException Exception writing to file [  ( fileSession is null ) ] offset: \"\n                                    + ((fileBlock == null) ? \" fileBlock is null\" : \"\" + fileBlock.fileOffset), t);\n                } else {\n                    logger.log(Level.SEVERE, myName + \" ... Got GeneralException Exception writing to file [  ( \"\n                            + fileSession.sessionID() + \" ): \" + fileSession.fileName() + \" ] offset: \"\n                            + ((fileBlock == null) ? \" fileBlock is null\" : \"\" + fileBlock.fileOffset), t);\n                }\n\n                if ((fdtSession != null) && (fileSession.sessionID() != null)) {\n                    fdtSession.finishFileSession(fileSession.sessionID(), t);\n                }\n            } finally {\n                try {\n                    if ((fileBlock != null) && (fileBlock.buff != null)) {\n                        bufferPool.put(fileBlock.buff);\n                    }\n                    fileBlock = null;\n                } catch (Throwable t) {\n                    logger.log(Level.SEVERE, myName + \" ... unable to return the buffer to the bufferPool\", t);\n                }\n            }\n\n        }// while()\n\n        try {\n            Utils.drainFileBlockQueue(queue);\n        } catch (Throwable t) {\n            logger.log(Level.SEVERE, \"Possbile buff loss from the pool\", t);\n        }\n\n        try {\n            Thread.currentThread().setName(cName);\n        } catch (Throwable t) {\n            // does not matter if did not succeed\n        }\n\n        stopIt();\n\n        logger.log(Level.INFO, myName + \" STOPPED! hasToRun() = \" + hasToRun.get());\n    }// run()\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/GenericDiskManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.AbstractFDTIOEntity;\nimport lia.util.net.copy.FDTSession;\n\nimport java.util.Collections;\nimport java.util.Set;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\n\n/**\n * Master class for both Read/Write managers\n *\n * @author ramiro\n */\nabstract class GenericDiskManager extends AbstractFDTIOEntity {\n\n    protected final SortedSet<FDTSession> sessions = Collections.synchronizedSortedSet(new TreeSet<FDTSession>());\n\n    public boolean removeSession(FDTSession fdtSession, String downMessage, Throwable downCause) {\n        if (sessions.remove(fdtSession)) {\n            fdtSession.close(downMessage, downCause);\n            return true;\n        }\n\n        return false;\n    }\n\n    public boolean addSession(FDTSession fdtSession) {\n        return sessions.add(fdtSession);\n    }\n\n    public final int sessionsSize() {\n        return sessions.size();\n    }\n\n    public Set<FDTSession> getSessions() {\n        return sessions;\n    }\n\n    public long getSize() {\n        return -1;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/GenericDiskTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.copy.AccountableEntity;\n\n/**\n * Base class for both Read/Write disk threads\n *\n * @author ramiro\n */\npublic abstract class GenericDiskTask extends AccountableEntity implements Runnable {\n\n    protected static final DirectByteBufferPool bufferPool = DirectByteBufferPool.getInstance();\n    protected final int partitionID;\n    protected final int taskID;\n    protected String myName;\n\n    public GenericDiskTask(final int partitionID, final int taskID) {\n        this.partitionID = partitionID;\n        this.taskID = taskID;\n    }\n\n    public long getSize() {\n        return -1;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/disk/ResumeManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.disk;\n\nimport lia.util.net.copy.FileSession;\n\nimport java.io.File;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is used to \"check\" if a {@link FileSession} is already copied or not\n * For the moment, two \"remote\" <code>{@link java.io.File}-s</code> are considered\n * equal only if they have the {@link java.io.File length} and {@link java.io.File lastModified} are the same for both\n * of them\n *\n * @author ramiro\n */\npublic class ResumeManager {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(ResumeManager.class.getName());\n\n    private static final ResumeManager _thisInstance = new ResumeManager();\n\n    public static final ResumeManager getInstance() {\n        return _thisInstance;\n    }\n\n    public boolean isFinished(FileSession fileSession) {\n\n        try {\n            if (fileSession.sessionSize() == 0) {\n                try {\n                    final File zeroF = fileSession.getFile();\n                    final File pzf = zeroF.getAbsoluteFile().getParentFile();\n                    if (!pzf.exists()) {\n                        if (!pzf.mkdirs()) {\n                            logger.log(Level.WARNING, \"Unable to create parent dirs for 0 size file: \" + zeroF);\n                        }\n                    }\n                    fileSession.getFile().createNewFile();\n                    fileSession.close(\"0 size file\", null);\n                    return true;\n                } catch (Throwable t1) {\n                    t1.printStackTrace();\n                }\n            }\n\n            if (fileSession.getFile().exists())\n                if (fileSession.sessionSize() == fileSession.getFile().length() && fileSession.lastModified() == fileSession.getFile().lastModified()) {\n                    return true;\n                }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING,\n                    \" [ ResumeManager ] Got exception checking if fileSession [ \" + fileSession.fileName() + \" / \" + fileSession.sessionID()\n                            + \" ] is finished \",\n                    t);\n        }\n\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/Postprocessor.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.filters;\n\nimport javax.security.auth.Subject;\n\n/**\n * Base class used to implement post filters plugins in FDT. The <code>Postprocessor</code>\n * is called after a FDT session finishes.\n *\n * @author ramiro\n */\npublic interface Postprocessor {\n    public void postProcessFileList(ProcessorInfo processorInfo, Subject peerSubject, Throwable downCause, String downMessage) throws Exception;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/Preprocessor.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.filters;\n\nimport javax.security.auth.Subject;\n\n/**\n * Base class used to implement pre filters plugins in FDT. The <code>Preprocessor</code>\n * is called before a FDT session starts.\n *\n * @author ramiro\n */\npublic interface Preprocessor {\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/ProcessorInfo.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.filters;\n\nimport lia.util.net.copy.FileSession;\n\nimport java.net.InetAddress;\nimport java.util.Arrays;\nimport java.util.Map;\n\n/**\n * This class encapsulates the file list which is to be, or has been transfered\n * and the destination directory.\n *\n * @author ramiro\n */\npublic class ProcessorInfo {\n\n    public String[] fileList;\n    public String destinationDir;\n    /**\n     * @since 0.9.25\n     */\n    public InetAddress remoteAddress;\n    /**\n     * @since 0.9.25\n     */\n    public int remotePort;\n    /**\n     * @since 0.9.25\n     */\n    public boolean recursive;\n\n    /**\n     * Non-null on writer side <b>ONLY</b>.\n     * </br>\n     * Gives access to the transfer map of an FDT session.\n     * </br>\n     * Key - the final file name (including the destination directory) for a {@link FileSession}</br>\n     * Value - the {@link FileSession}</br>\n     *\n     * @see FileSession\n     * @since 0.10.0\n     */\n    public Map<String, FileSession> fileSessionMap;\n\n    /* (non-Javadoc)\n     * @see java.lang.Object#toString()\n     */\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"ProcessorInfo [destinationDir=\")\n                .append(destinationDir)\n                .append(\", remoteAddress=\")\n                .append(remoteAddress)\n                .append(\", remotePort=\")\n                .append(remotePort)\n                .append(\", recursive=\")\n                .append(recursive)\n                .append(\", fileList=\")\n                .append(Arrays.toString(fileList))\n                .append(\", fileSessionMap=\")\n                .append(fileSessionMap)\n                .append(\"]\");\n        return builder.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/FirewallFileExtension.java",
    "content": "package lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.FileSession;\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport java.util.regex.Pattern;\n\n/**\n * <p>\n * Simple example which filters some files based on a suffix passed as a Java environment variable\n * You may pass a config file as an environment variable, a regex, etc ...\n * </p>\n * <p>\n * This filter can be used directly (as it ships with the fdt.jar):\n * </p>\n * <pre>java -DFirewallFileExtension.suffix=\"/some/path/TMP_TEST\" -jar fdt.jar ... other params</pre>\n *\n * @author Raimondas Sirvinskas\n * @see Pattern\n */\npublic class FirewallFileExtension implements Preprocessor {\n\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(FirewallFileExtension.class.getName());\n\n    /**\n     * @param processorInfo\n     * @param peerSubject   - not used\n     */\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception {\n\n        final Map<String, FileSession> fileSessionMap = processorInfo.fileSessionMap;\n        final String firewallSuffix = System.getProperty(\"FirewallFileExtension.suffix\");\n        if (firewallSuffix == null || firewallSuffix.trim().isEmpty()) {\n            logger.log(Level.INFO, \"[ FirewallFileNames ] No suffix defined\");\n            return;\n        }\n\n        final String firewallSuffixTrim = firewallSuffix.trim();\n        logger.log(Level.INFO, \" [ FirewallFileNames ] firewall suffix pattern=\" + firewallSuffixTrim);\n\n        for (Iterator<Map.Entry<String, FileSession>> iterator = fileSessionMap.entrySet().iterator(); iterator.hasNext(); ) {\n            final Map.Entry<String, FileSession> entry = iterator.next();\n            final FileSession fileSession = entry.getValue();\n            final String fName = fileSession.fileName();\n            logger.log(Level.INFO, \"[ FirewallFileNames ] fname = \" + fName);\n            if (fName.endsWith(firewallSuffixTrim)) {\n                logger.log(Level.INFO, \"FNAME firewalled: \" + fName);\n                iterator.remove();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/FirewallFileNames.java",
    "content": "package lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.FileSession;\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\n/**\n * <p>\n * Simple example which filters some files based on a prefix passed as a Java environment variable\n * You may pass a config file as an environment variable, a regex, etc ...\n * </p>\n * <p>\n * This filter can be used directly (as it ships with the fdt.jar):\n * </p>\n * <pre>java -DFirewallFileNames.prefix=\"/some/path/TMP_TEST\" -jar fdt.jar ... other params</pre>\n *\n * @author ramiro\n * @see Pattern\n */\npublic class FirewallFileNames implements Preprocessor {\n\n    /**\n     * @param processorInfo\n     * @param peerSubject   - not used\n     */\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception {\n\n        final Map<String, FileSession> fileSessionMap = processorInfo.fileSessionMap;\n\n        final String firewallPrefix = System.getProperty(\"FirewallFileNames.prefix\");\n        if (firewallPrefix == null || firewallPrefix.trim().isEmpty()) {\n            System.out.println(\"[ FirewallFileNames ] No prefix defined\");\n            return;\n        }\n\n        final String firewallPrefixTrim = firewallPrefix.trim();\n\n        System.out.println(\" [ FirewallFileNames ] firewall prefix pattern=\" + firewallPrefixTrim);\n\n        for (Iterator<Map.Entry<String, FileSession>> iterator = fileSessionMap.entrySet().iterator(); iterator.hasNext(); ) {\n            final Map.Entry<String, FileSession> entry = iterator.next();\n            final FileSession fileSession = entry.getValue();\n            //System.out.println(\"Key: \" + key);\n            //System.out.println(\"FileSession: \" + fileSession);\n\n            final String fName = fileSession.fileName();\n            System.out.println(\"[ FirewallFileNames ] fname = \" + fName);\n            if (fName.startsWith(firewallPrefixTrim)) {\n                System.out.println(\"FNAME firewalled: \" + fName);\n                iterator.remove();\n            } else {\n                //System.out.println(\"FNAME passed: \" + fName);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/FixUserHome.java",
    "content": "package lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.FileSession;\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.util.Iterator;\nimport java.util.Map;\n\n/**\n * Simple example which replaces the file names on the writer side\n *\n * @author ramiro\n */\npublic class FixUserHome implements Preprocessor {\n\n\n    /**\n     * @param processorInfo\n     * @param peerSubject   - not used\n     */\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception {\n\n        final Map<String, FileSession> fileSessionMap = processorInfo.fileSessionMap;\n        final String destDirName = processorInfo.destinationDir;\n        final int dLen = destDirName.length();\n\n        final String userName = System.getProperty(\"user.name\");\n        final String userHome = System.getProperty(\"user.home\");\n\n        System.out.println(\"FixUserHome for user '\" + userName + \"' and $HOME '\" + userHome + \"' \");\n\n        for (Iterator<Map.Entry<String, FileSession>> iterator = fileSessionMap.entrySet().iterator(); iterator.hasNext(); ) {\n            Map.Entry<String, FileSession> entry = iterator.next();\n            final String key = entry.getKey();\n            final FileSession fileSession = entry.getValue();\n            System.out.println(\"Key: \" + key);\n            System.out.println(\"FileSession: \" + fileSession);\n\n            final String fName = fileSession.fileName();\n            // final String newFName = destDirName.replace(\"~\", \"/home/ramiro\") + fName.substring(dLen);\n\n            //\n            // TODO - Check if needs to be replaced. \n            //\n\n            final String newFName = destDirName.replace(\"~\", userHome) + fName.substring(dLen);\n            // file separator + ~\n            System.out.println(\" ----> OLD: \" + fName + \" <--->  NEW: \" + newFName + \" <--- \");\n\n            fileSession.setFileName(newFName);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/PostRename.java",
    "content": "package lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.filters.Postprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.io.File;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Raimondas Sirvinskas\n * @version 1.0\n */\npublic class PostRename implements Postprocessor {\n\n    public static final String PREFIX = \"prefix\";\n    public static final String DEFAULT_PREFIX = \"RENAMED_\";\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(PostRename.class.getName());\n\n    public void postProcessFileList(ProcessorInfo processorInfo, Subject peerSubject, Throwable downCause, String downMessage) throws Exception {\n        logger.log(Level.INFO, \" [ PostRename ] Subject: \" + peerSubject);\n        String filePrefix = System.getProperty(PREFIX, DEFAULT_PREFIX);\n\n        for (int i = 0; i < processorInfo.fileList.length; i++) {\n            try {\n                String name = processorInfo.fileList[i];\n                final String outFilename = processorInfo.destinationDir + File.separator + filePrefix + name;\n                final String orgFileName = processorInfo.destinationDir + File.separator + name;\n                logger.log(Level.INFO, \"Renaming file: \" + name + \" to: \" + filePrefix + name);\n                new File(orgFileName).renameTo(new File(outFilename));\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/PostZipFilter.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.filters.Postprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.OutputStream;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\n/**\n * Simple postProcess FDT Filter. It decompresses the zip files received\n * from the remote peer and then deletes the archives files.\n *\n * @author ramiro\n */\npublic class PostZipFilter implements Postprocessor {\n\n    public void postProcessFileList(ProcessorInfo processorInfo, Subject peerSubject, Throwable downCause, String downMessage) throws Exception {\n\n        System.out.println(\" [ PostZipFilter ] Subject: \" + peerSubject);\n\n        for (int i = 0; i < processorInfo.fileList.length; i++) {\n\n            // Open the ZIP file\n            final String inFilename = processorInfo.destinationDir + File.separator + processorInfo.fileList[i];\n            ZipInputStream in = new ZipInputStream(new FileInputStream(inFilename));\n\n            // Get the first entry\n            final ZipEntry entry = in.getNextEntry();\n\n            // Open the output file\n            String outFilename = inFilename.substring(0, inFilename.length() - 4);\n            OutputStream out = new FileOutputStream(outFilename);\n\n            // Transfer bytes from the ZIP file to the output file\n            byte[] buf = new byte[1024];\n            int len;\n            while ((len = in.read(buf)) > 0) {\n                out.write(buf, 0, len);\n            }\n\n            // Close the streams\n            out.close();\n            in.close();\n\n            //delete the zip file!\n            new File(inFilename).delete();\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/PreRename.java",
    "content": "package lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.io.File;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Raimondas Sirvinskas\n * @version 1.0\n */\npublic class PreRename implements Preprocessor {\n\n    public static final String PREFIX = \"prefix\";\n    public static final String DEFAULT_PREFIX = \"NEW_FILE_\";\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(PreRename.class.getName());\n\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) {\n        logger.log(Level.INFO, \" [ PreRename ] Subject: \" + peerSubject);\n        String filePrefix = System.getProperty(PREFIX, DEFAULT_PREFIX);\n\n        for (int i = 0; i < processorInfo.fileList.length; i++) {\n            try {\n                final String outFilename = processorInfo.destinationDir + File.separator + filePrefix + processorInfo.fileList[i];\n                logger.log(Level.INFO, \"Renaming file: \" + processorInfo.fileList[i] + \" to: \" + outFilename);\n                processorInfo.fileList[i] = outFilename;\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/filters/examples/PreZipFilter.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.filters.examples;\n\nimport lia.util.net.copy.filters.Preprocessor;\nimport lia.util.net.copy.filters.ProcessorInfo;\n\nimport javax.security.auth.Subject;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\n\n/**\n * Simple preProcess FDT Filter. It compress every file list specified in the\n * file list, saves it as a .zip and modifies the file name and returns the\n * file list to the FDT, which sends the zip files to the destination\n *\n * @author ramiro\n */\npublic class PreZipFilter implements Preprocessor {\n\n    public void preProcessFileList(ProcessorInfo processorInfo, Subject peerSubject) throws Exception {\n\n        System.out.println(\" [ PreZipFilter ] Subject: \" + peerSubject);\n\n        for (int i = 0; i < processorInfo.fileList.length; i++) {\n\n            // Create a buffer for reading the files\n            byte[] buf = new byte[1024];\n\n            // Create the ZIP file\n            final String outFilename = processorInfo.fileList[i] + \".zip\";\n            ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outFilename));\n\n            // Compress the files\n            FileInputStream in = new FileInputStream(processorInfo.fileList[i]);\n\n            // Add ZIP entry to output stream.\n            out.putNextEntry(new ZipEntry(processorInfo.fileList[i]));\n\n            // Transfer bytes from the file to the ZIP file\n            int len;\n            while ((len = in.read(buf)) > 0) {\n                out.write(buf, 0, len);\n            }\n\n            // Complete the entry\n            out.closeEntry();\n            in.close();\n\n            // Complete the ZIP file\n            out.close();\n\n            //rename the file in the config\n            processorInfo.fileList[i] = outFilename;\n\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/AboutDialog.java",
    "content": "/*\n * $Id: AboutDialog.java 474 2007-10-11 11:38:24Z cipsm $ \n */\npackage lia.util.net.copy.gui;\n\nimport lia.util.net.copy.FDT;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.*;\nimport java.lang.reflect.Method;\nimport java.net.URL;\n\n/**\n * @author Ciprian Dobre\n */\npublic class AboutDialog extends JDialog {\n\n//\tstatic final String help1 = \"<html><p align=center>FDT - Fast Data Transfer</p></html>\";\n//\tstatic final String help2 = \"<html><!--<br>&copy California Institute of Technology--></p></html>\";\n\n    private static final Object basicServiceObject = getBasicServiceObject();\n    private static final Class basicServiceClass = getBasicServiceClass();\n    private ImageIcon caltechIcon;\n\n    public AboutDialog(JFrame parent) {\n        super(parent, \"About...\", true);\n        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));\n\n        JLabel l1 = new JLabel(\"<html><p align=center>FDT - Fast Data Transfer</p></html>\", JLabel.CENTER);\n        JPanel p1 = new JPanel();\n        p1.setLayout(new BorderLayout());\n        p1.add(l1, BorderLayout.CENTER);\n        getContentPane().add(p1);\n\n        l1 = new JLabel(\"<html><p align=center><font color=#ff0000>http://monalisa.cern.ch/FDT</font></p></html>\", JLabel.CENTER);\n        l1.addMouseListener(new MouseAdapter() {\n            public void mouseClicked(MouseEvent e) {\n                try {\n                    URL u = new URL(\"http://monalisa.cern.ch/FDT\");\n                    showDocument(u);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n        });\n        p1 = new JPanel();\n        p1.setLayout(new BorderLayout());\n        p1.add(l1, BorderLayout.CENTER);\n        getContentPane().add(p1);\n\n//\t\tString version = \"<html><p align=center>Version <font color=#ff0000>\"+FDT.FDT_FULL_VERSION+\"</font></p></html>\";\n        l1 = new JLabel(\"<html><p align=center>Version <font color=#ff0000>\" + FDT.FDT_FULL_VERSION + \"</font></p></html>\", JLabel.CENTER);\n        p1 = new JPanel();\n        p1.setLayout(new BorderLayout());\n        p1.add(l1, BorderLayout.CENTER);\n        getContentPane().add(p1);\n\n        l1 = new JLabel(getCaltechIcon());\n        p1 = new JPanel();\n        p1.add(l1, BorderLayout.CENTER);\n        getContentPane().add(p1);\n\n        setVisible(false);\n        setSize(200, 100);\n        setBackground(new Color(15724527));\n//\t\tsetTitle(\"About...\");\n        setResizable(false);\n\n        JButton okButton = new JButton(\"OK\");\n        okButton.setMinimumSize(new Dimension(190, 22));\n        okButton.setPreferredSize(new Dimension(190, 22));\n        p1 = new JPanel();\n        p1.setLayout(new BorderLayout());\n        p1.add(okButton, BorderLayout.CENTER);\n        getContentPane().add(p1);\n        okButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                setVisible(false);\n            }\n        });\n        pack();\n    }\n\n    public static boolean showDocument(URL url) {\n        if (basicServiceObject == null) {\n            return false;\n        }\n        try {\n            Method method = basicServiceClass.getMethod(\"showDocument\", new Class[]{URL.class});\n            Boolean resultBoolean = (Boolean) method.invoke(basicServiceObject, new Object[]{url});\n            return resultBoolean.booleanValue();\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            throw new RuntimeException(ex.getMessage());\n        }\n    }\n\n    private static Object getBasicServiceObject() {\n        try {\n            Class serviceManagerClass = Class.forName(\"javax.jnlp.ServiceManager\");\n            Method lookupMethod = serviceManagerClass.getMethod(\"lookup\", new Class[]{String.class});\n            return lookupMethod.invoke(null, new Object[]{\"javax.jnlp.BasicService\"});\n        } catch (Exception ex) {\n            return null;\n        }\n    }\n\n    private static Class getBasicServiceClass() {\n        try {\n            return Class.forName(\"javax.jnlp.BasicService\");\n        } catch (Exception ex) {\n            return null;\n        }\n    }\n\n    /**\n     * Shows or hides the component depending on the Boolean flag b.\n     *\n     * @param b if true, show the component; otherwise, hide the\n     *          component.\n     * @See java.awt.Component#isVisible\n     */\n    public void setVisible(boolean b) {\n        if (b) {\n            Dimension bounds = Toolkit.getDefaultToolkit().getScreenSize();\n            Dimension abounds = getSize();\n            setLocation((bounds.width - abounds.width) / 2, (bounds.height - abounds.height) / 3);\n        }\n        super.setVisible(b);\n    }\n\n    public Icon getCaltechIcon() {\n        if (caltechIcon != null) return caltechIcon;\n        try {\n            URL url = getClass().getResource(\"icons/caltech.gif\");\n            caltechIcon = new ImageIcon(url);\n        } catch (Throwable t) {\n        }\n        return caltechIcon;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/ClientSessionManager.java",
    "content": "/*\n * $Id: ClientSessionManager.java 643 2011-02-13 15:00:30Z catac $\n */\npackage lia.util.net.copy.gui;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.HeaderBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.FDTSessionManager;\nimport lia.util.net.copy.monitoring.ConsoleReportingTask;\nimport lia.util.net.copy.monitoring.FDTInternalMonitoringTask;\nimport lia.util.net.copy.monitoring.FDTSessionMonitoringTask;\nimport lia.util.net.copy.transport.TCPTransportProvider;\n\nimport java.lang.reflect.Field;\nimport java.text.NumberFormat;\nimport java.util.HashMap;\nimport java.util.concurrent.RunnableScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Ciprian Dobre\n */\npublic class ClientSessionManager {\n\n    static final transient Logger logger = Logger.getLogger(ClientSessionManager.class.getCanonicalName());\n    private static final long KILO_BIT = 1000;\n    private static final long MEGA_BIT = KILO_BIT * 1000;\n    private static final long GIGA_BIT = MEGA_BIT * 1000;\n    private static final long TERA_BIT = GIGA_BIT * 1000;\n    private static final long PETA_BIT = TERA_BIT * 1000;\n    private final static NumberFormat nf = NumberFormat.getInstance();\n\n    static {\n        nf.setMaximumFractionDigits(2);\n    }\n\n    private FDTSession currentSession;\n    private FDTSessionMonitoringTask fdtSessionMTask;\n    private RunnableScheduledFuture fdtInternalMonitoringTask = null;\n    private RunnableScheduledFuture consoleReporting = null;\n\n    //do it nicer - TODO make same arrays and use for() ... it's not the 5th grade\n    private static final String formatNetSpeed(final double number, final String append) {\n        String appendUM;\n        double fNo = number;\n\n        if (number > PETA_BIT) {\n            fNo /= PETA_BIT;\n            appendUM = \"P\" + append;\n        } else if (number > TERA_BIT) {\n            fNo /= TERA_BIT;\n            appendUM = \"T\" + append;\n        } else if (number > GIGA_BIT) {\n            fNo /= GIGA_BIT;\n            appendUM = \"G\" + append;\n        } else if (number > MEGA_BIT) {\n            fNo /= MEGA_BIT;\n            appendUM = \"M\" + append;\n        } else if (number > KILO_BIT) {\n            fNo /= KILO_BIT;\n            appendUM = \"K\" + append;\n        } else {\n            appendUM = append;\n        }\n\n        return nf.format(fNo) + \" \" + appendUM;\n    }\n\n    /**\n     * Called in order to initialize a connection with a remote port...\n     *\n     * @param host\n     * @param port\n     */\n    public String initTransfer(final String host, final int port, final boolean isPullMode,\n                               final String[] fileList, final String destDir, final FDTPropsDialog d, final boolean isRecursive) {\n        // start by constructing a dummy config\n        constructConfig(host, port, isPullMode, fileList, destDir, d, isRecursive);\n        HeaderBufferPool.initInstance();\n        fdtInternalMonitoringTask = (RunnableScheduledFuture) Utils.getMonitoringExecService().scheduleWithFixedDelay(FDTInternalMonitoringTask.getInstance(), 1, 5, TimeUnit.SECONDS);\n        consoleReporting = (RunnableScheduledFuture) Utils.getMonitoringExecService().scheduleWithFixedDelay(ConsoleReportingTask.getInstance(), 1, 2, TimeUnit.SECONDS);\n        // the session manager will check the \"pull/push\" mode and start the FDTSession\n        try {\n            currentSession = FDTSessionManager.getInstance().addFDTClientSession(port);\n            fdtSessionMTask = currentSession.getMonitoringTask();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception when initiating transfer\", t);\n            return t.getLocalizedMessage();\n        }\n        return null;\n    }\n\n    public FDTSession currentSession() {\n        return currentSession;\n    }\n\n    public void cancelTransfer() {\n        if (currentSession == null) return;\n        currentSession.close(\"User pressed cancel\", new Exception(\"User pressed cancel\"));\n        currentSession = null;\n        fdtSessionMTask = null;\n    }\n\n    public void end() {\n        if (fdtInternalMonitoringTask != null) {\n            Utils.getMonitoringExecService().remove(fdtInternalMonitoringTask);\n            fdtInternalMonitoringTask = null;\n        }\n        if (consoleReporting != null) {\n            Utils.getMonitoringExecService().remove(consoleReporting);\n            consoleReporting = null;\n        }\n        Utils.getMonitoringExecService().purge();\n    }\n\n    public double transferProgress() {\n        if (currentSession == null) {\n            return 100.0;\n        }\n\n        TCPTransportProvider tcpTransportProvider = currentSession.getTransportProvider();\n        if (tcpTransportProvider == null) {\n            return 0.0;\n        }\n\n        if (tcpTransportProvider.isClosed()) {\n            logger.warning(\"Transport is closed\");\n            return 100.0;\n        }\n        final double tSize = currentSession.getSize();\n\n        final long tcpSize = tcpTransportProvider.getUtilBytes();\n        final double cSize = (tcpSize <= 0L) ? 0D : tcpSize;\n\n        double percent = 100.0;\n        try {\n            percent = Math.min((cSize * 100.0) / (double) tSize, 100.0);\n        } catch (Exception e) {\n        }\n        if (!Double.isNaN(percent) && !Double.isInfinite(percent) && percent >= 100.0) {\n            try {\n                int state = currentSession.currentState();\n                boolean endRcv = ((state & FDTSession.END_RCV) == FDTSession.END_RCV);\n                boolean endSnt = ((state & FDTSession.END_SENT) == FDTSession.END_SENT);\n                if (((state & FDTSession.TRANSFERING) == FDTSession.TRANSFERING) || (!endRcv && !endSnt)) {\n                    return 99.99;\n                }\n            } catch (Throwable t) {\n                t.printStackTrace();\n            }\n        }\n        return percent;\n    }\n\n    public String currentSpeed() {\n        if (currentSession == null) return \"0.0 b/s\";\n        try {\n            if (currentSession.getTransportProvider() != null && currentSession.getTransportProvider().isClosed()) {\n                logger.warning(\"Transport is closed\");\n                return \"0.0 b/s\";\n            }\n            double rate = currentSession.getTransportProvider().monitoringTask.getTotalRate() * 8;\n            return formatNetSpeed(rate, \"b/s\");\n        } catch (Throwable t) {\n            return \"0.0 b/s\";\n        }\n    }\n\n    /**\n     * Constructs a Config object based on provided arguments..\n     */\n    private final void constructConfig(final String host, final int port, final boolean isPullMode,\n                                       final String[] fileList, final String destDir, final FDTPropsDialog d, final boolean isRecursive) {\n        // first set the initialized flag on false....\n        Class c = Config.class;\n        // construct the hashmap\n        try {\n            Config.initInstance(new HashMap<String, Object>());\n        } catch (Throwable t1) {\n            t1.printStackTrace();\n        }\n        Config conf = Config.getInstance();\n        // shall I get the data from server? - used only by the client\n        try {\n            conf.setHostName(host);\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"portNo\");\n            f.setAccessible(true);\n            f.set(conf, port);\n        } catch (Throwable t) {\n        }\n        try {\n            conf.setPullMode(isPullMode);\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n        try {\n            Field f = c.getDeclaredField(\"fileList\");\n            f.setAccessible(true);\n            f.set(conf, fileList);\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"destDir\");\n            f.setAccessible(true);\n            f.set(conf, destDir);\n        } catch (Throwable t) {\n        }\n        System.out.println(\"hostname = \" + conf.getHostName());\n        System.out.println(\"port = \" + conf.getPort());\n        String files[] = conf.getFileList();\n        for (int i = 0; i < files.length; i++)\n            System.out.println(files[i]);\n        System.out.println(\"dest = \" + conf.getDestinationDir());\n        System.out.println(\"isPull=\" + conf.isPullMode());\n        if (d == null) return;\n        try {\n            Field f = c.getDeclaredField(\"sockBufSize\");\n            f.setAccessible(true);\n            f.set(conf, d.getSockBufSize());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"sockNum\");\n            f.setAccessible(true);\n            f.set(conf, d.getSockNum());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"rateLimit\");\n            f.setAccessible(true);\n            f.set(conf, d.getRateLimit());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"readersCount\");\n            f.setAccessible(true);\n            f.set(conf, d.getReadersCount());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"writersCount\");\n            f.setAccessible(true);\n            f.set(conf, d.getWritersCount());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"maxPartitionsCount\");\n            f.setAccessible(true);\n            f.set(conf, d.getMaxPartitionsCount());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"bComputeMD5\");\n            f.setAccessible(true);\n            f.set(conf, d.isBComputeMD5());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"bRecursive\");\n            f.setAccessible(true);\n            f.set(conf, isRecursive);\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"bUseFixedBlocks\");\n            f.setAccessible(true);\n            f.set(conf, d.isBUseFixedBlocks());\n        } catch (Throwable t) {\n        }\n        try {\n            Field f = c.getDeclaredField(\"transferLimit\");\n            f.setAccessible(true);\n            f.set(conf, d.getTransferLimit());\n        } catch (Throwable t) {\n        }\n    }\n\n} // end of class ClientSessionManager\n\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/ConnectDialog.java",
    "content": "/*\n * $Id: ConnectDialog.java 422 2007-09-04 13:23:15Z cipsm $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.*;\n\n/**\n * @author Ciprian Dobre\n */\npublic class ConnectDialog extends JDialog implements KeyListener, ItemListener {\n\n    final JFrame parent;\n    public String sHost = \"localhost\", sPort = \"54321\", sUser = System.getProperty(\"user.name\");\n    public boolean bDialogOK = false;\n    private JTextField textHost = new JTextField();\n    private JTextField textPort = new JTextField();\n    private JTextField textUser = new JTextField();\n    private JCheckBox useSSH = new JCheckBox(\"Connect using ssh\");\n\n    public ConnectDialog(JFrame f) {\n        super(f, \"Connection preferences\", true);\n\n        JPanel mainPanel = new EnhancedJPanel();\n        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));\n\n        this.parent = f;\n        JPanel p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\n        mainPanel.add(p);\n        p.add(new JLabel(\"Remote Hostname: \"));\n        try {\n            sHost = PreferencesHandler.get(\"hostname\", \"localhost\");\n        } catch (Throwable t) {\n        }\n        textHost.setText(sHost);\n        textHost.addKeyListener(this);\n        p.add(textHost);\n\n        boolean useSSH = true;\n        try {\n            useSSH = Boolean.valueOf(PreferencesHandler.get(\"useSSH\", \"true\"));\n        } catch (Throwable t) {\n        }\n\n        p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\n        mainPanel.add(p);\n        p.add(new JLabel(\"Remote Username: \"));\n        try {\n            sUser = PreferencesHandler.get(\"user\", sUser);\n        } catch (Throwable t) {\n        }\n        textUser.setText(sUser);\n        textUser.addKeyListener(this);\n        p.add(textUser);\n        textUser.setEnabled(useSSH);\n\n        p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\n        mainPanel.add(p);\n        this.useSSH.setSelected(useSSH);\n        this.useSSH.addItemListener(this);\n        this.useSSH.setOpaque(false);\n        p.add(this.useSSH);\n        p.add(Box.createHorizontalGlue());\n\n        p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\n        mainPanel.add(p);\n        p.add(new JLabel(\"FDT Port Number: \"));\n        try {\n            sPort = PreferencesHandler.get(\"port\", \"54321\");\n        } catch (Throwable t) {\n        }\n        textPort.setText(sPort);\n        textPort.addKeyListener(this);\n        p.add(textPort);\n\n        p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new GridLayout(0, 2));\n        mainPanel.add(p);\n        JButton bOK = new JButton(\"OK\");\n        bOK.addKeyListener(this);\n        bOK.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent arg0) {\n                sHost = textHost.getText();\n                sPort = textPort.getText();\n                if (textUser.isEnabled())\n                    sUser = textUser.getText();\n                else\n                    sUser = null;\n                if (sHost == null || sHost.length() == 0) {\n                    JOptionPane.showMessageDialog(parent, \"You must enter the hostname\");\n                    return;\n                }\n                if (textUser.isEnabled() && (sUser == null || sUser.length() == 0)) {\n                    JOptionPane.showMessageDialog(parent, \"You must enter a valid username\");\n                    return;\n                }\n                if (sPort == null || sPort.length() == 0) {\n                    JOptionPane.showMessageDialog(parent, \"You must enter a valid port number\");\n                    return;\n                }\n                try {\n                    Integer.parseInt(sPort);\n                } catch (Throwable t) {\n                    JOptionPane.showMessageDialog(parent, \"You must enter a valid port number\");\n                }\n                PreferencesHandler.put(\"hostname\", sHost);\n                if (textUser.isEnabled())\n                    PreferencesHandler.put(\"user\", sUser);\n                PreferencesHandler.put(\"port\", sPort);\n                PreferencesHandler.save();\n                bDialogOK = true;\n                setVisible(false);\n            }\n        });\n        p.add(bOK);\n        JButton bCancel = new JButton(\"Cancel\");\n        bCancel.addKeyListener(this);\n        bCancel.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent arg0) {\n                bDialogOK = false;\n                setVisible(false);\n            }\n        });\n        p.add(bCancel);\n        getContentPane().setLayout(new BorderLayout(2, 2));\n        getContentPane().add(mainPanel, BorderLayout.CENTER);\n        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);\n        setSize(330, 330);\n        setLocationRelativeTo(parent);\n        pack();\n    }\n\n    public void itemStateChanged(ItemEvent e) {\n        if (e.getStateChange() == ItemEvent.DESELECTED) {\n            textUser.setEnabled(false);\n            PreferencesHandler.put(\"useSSH\", \"false\");\n            PreferencesHandler.save();\n        } else {\n            textUser.setEnabled(true);\n            PreferencesHandler.put(\"useSSH\", \"true\");\n            PreferencesHandler.save();\n        }\n    }\n\n    public void keyTyped(KeyEvent e) {\n    }\n\n    public void keyPressed(KeyEvent e) {\n    }\n\n    public void keyReleased(KeyEvent e) {\n        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {\n            bDialogOK = false;\n            setVisible(false);\n            return;\n        }\n        if (e.getKeyCode() == KeyEvent.VK_ENTER) {\n            sHost = textHost.getText();\n            sPort = textPort.getText();\n            if (textUser.isEnabled())\n                sUser = textUser.getText();\n            else\n                sUser = null;\n            if (sHost == null || sHost.length() == 0) {\n                JOptionPane.showMessageDialog(parent, \"You must enter the hostname\");\n                return;\n            }\n            if (textUser.isEnabled() && (sUser == null || sUser.length() == 0)) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid username\");\n                return;\n            }\n            if (sPort == null || sPort.length() == 0) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid port number\");\n                return;\n            }\n            try {\n                Integer.parseInt(sPort);\n            } catch (Throwable t) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid port number\");\n            }\n            PreferencesHandler.put(\"hostname\", sHost);\n            if (textUser.isEnabled())\n                PreferencesHandler.put(\"user\", sUser);\n            PreferencesHandler.put(\"port\", sPort);\n            PreferencesHandler.save();\n            bDialogOK = true;\n            setVisible(false);\n            return;\n        }\n    }\n\n    public void setVisible(boolean v) {\n        if (v) {\n            setLocationRelativeTo(parent);\n            toFront();\n            pack();\n        }\n        super.setVisible(v);\n    }\n\n} // end of class ConnectDialog\n\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/CustomLogHandler.java",
    "content": "package lia.util.net.copy.gui;\n\nimport java.util.Date;\nimport java.util.logging.Formatter;\nimport java.util.logging.Handler;\nimport java.util.logging.LogRecord;\n\n/**\n * A custom class designed to handle the logging messages to be also outputed to the StatusBar of the gui\n *\n * @author cipsm\n */\npublic class CustomLogHandler extends Handler {\n\n    private final StatusBar status;\n    private final MyCustomFormatter formatter;\n\n    public CustomLogHandler(final StatusBar status) {\n        super();\n        this.status = status;\n        formatter = new MyCustomFormatter();\n    }\n\n    private void setStatus(String status) {\n        if (this.status == null) return;\n        this.status.addText(status);\n    }\n\n    /* (non-API documentation)\n     * @see java.util.logging.Handler#publish(java.util.logging.LogRecord)\n     */\n    public void publish(LogRecord record) {\n        // ensure that this log record should be logged by this Handler\n        if (!isLoggable(record))\n            return;\n        setStatus(formatter.format(record));\n    }\n\n    /* (non-API documentation)\n     * @see java.util.logging.Handler#flush()\n     */\n    public void flush() {\n    }\n\n    /* (non-API documentation)\n     * @see java.util.logging.Handler#close()\n     */\n    public void close() throws SecurityException {\n    }\n\n    class MyCustomFormatter extends Formatter {\n\n        public MyCustomFormatter() {\n            super();\n        }\n\n        public String format(LogRecord record) {\n\n            // Create a StringBuffer to contain the formatted record\n            // start with the date.\n            StringBuffer sb = new StringBuffer();\n\n            sb.append(\"<font color=#ff0000>\");\n\n            // Get the date from the LogRecord and add it to the buffer\n            Date date = new Date(record.getMillis());\n            sb.append(date.toString());\n            sb.append(\" \");\n\n            // get the name of the class\n            sb.append(record.getSourceClassName());\n            sb.append(\" \");\n\n            // get the name of the method\n            sb.append(record.getSourceMethodName().replace(\"<\", \"[\").replace(\">\", \"]\"));\n            sb.append(\"\\n\");\n\n            // Get the level name and add it to the buffer\n            sb.append(record.getLevel().getName());\n            sb.append(\": \");\n\n            // Get the formatted message (includes localization\n            // and substitution of paramters) and add it to the buffer\n            sb.append(formatMessage(record).replace(\"<\", \"[\").replace(\">\", \"]\"));\n            sb.append(\"\\n\");\n\n            sb.append(\"</font>\");\n\n            return sb.toString();\n        }\n    }\n\n} // end of class CustomLogHandler\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/CustomPrintStream.java",
    "content": "package lia.util.net.copy.gui;\n\nimport java.io.OutputStream;\nimport java.io.PrintStream;\n\n/**\n * A custom PrintStream that is designed to capture println and output it into the status panel as well\n *\n * @author cipsm\n */\npublic class CustomPrintStream extends PrintStream {\n\n    private final StatusBar status;\n    private final String color;\n\n    public CustomPrintStream(final StatusBar status, OutputStream out, String color) {\n        super(out);\n        this.status = status;\n        this.color = color;\n    }\n\n    private void setStatus(String status) {\n        if (this.status == null) return;\n        status = status.replace(\"<\", \"[\").replace(\">\", \"]\");\n        this.status.addText(\"<font color=\" + color + \">\" + status + \"</font>\");\n    }\n\n    public void println(String string) {\n        super.print(string.toCharArray());\n        setStatus(string);\n        print(\"\\n\");\n    }\n\n    public void println() {\n        super.println();\n        setStatus(\"\\n\");\n    }\n\n    public void print(String string) {\n        super.print(string);\n        setStatus(string);\n    }\n\n} // end of class CustomPrintStream\n\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/DummyRemoteSessionManager.java",
    "content": "/*\r\n * $Id: DummyRemoteSessionManager.java 405 2007-09-03 14:48:03Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui;\r\n\r\nimport lia.util.net.copy.transport.gui.FileHandler;\r\n\r\nimport java.util.Vector;\r\n\r\n/**\r\n * Dummy class to test the remote session manager class\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class DummyRemoteSessionManager extends RemoteSessionManager {\r\n\r\n    int count = 0;\r\n\r\n    public DummyRemoteSessionManager(FDTPropsDialog props) {\r\n        super(props, null);\r\n    }\r\n\r\n    /**\r\n     * Receives the current directory of the session.. (default user home)\r\n     */\r\n    public String getWorkingDirectory() {\r\n        return System.getProperty(\"user.dir\");\r\n    }\r\n\r\n    /**\r\n     * Receives the name of the operating system\r\n     */\r\n    public String getOSName() {\r\n        return \"Linux\";\r\n    }\r\n\r\n    /**\r\n     * Return true if the current working dirctory is a root (no upper level)\r\n     */\r\n    public boolean isRoot() {\r\n        return true;\r\n    }\r\n\r\n    /**\r\n     * Receives the list of current files and folder in the current directory of the session\r\n     */\r\n    public Vector<FileHandler> getFileList() {\r\n        Vector<FileHandler> v = new Vector<FileHandler>();\r\n        // add two folders...\r\n        v.add(new FileHandler(\"dir1\", System.currentTimeMillis(), -1, false, true));\r\n        v.add(new FileHandler(\"dir2\", System.currentTimeMillis(), -1, true, true));\r\n        // now add some files\r\n        v.add(new FileHandler(\"image.png\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, false));\r\n        v.add(new FileHandler(\"image.gif\", System.currentTimeMillis(), (int) (Math.random() * 100000), false, false));\r\n        v.add(new FileHandler(\"image.jpeg\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, true));\r\n        v.add(new FileHandler(\"cd.iso\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, false));\r\n        v.add(new FileHandler(\"file.doc\", System.currentTimeMillis(), (int) (Math.random() * 100000), false, true));\r\n        v.add(new FileHandler(\"file.ppt\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, false));\r\n        v.add(new FileHandler(\"file.txt\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, true));\r\n        v.add(new FileHandler(\"dummy\", System.currentTimeMillis(), (int) (Math.random() * 100000), true, false));\r\n        return v;\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory to an absolute pathname\r\n     */\r\n    public void setAbsoluteDir(String dir) {\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory to a relative to the current dir pathname\r\n     */\r\n    public void setRelativeDir(String dir) {\r\n        try {\r\n            Thread.sleep(10000);\r\n        } catch (Exception e) {\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory up one level\r\n     */\r\n    public void setUpDir() {\r\n    }\r\n\r\n    /**\r\n     * Receives the known root pathes of the remote FS\r\n     */\r\n    public String[] getRoots() {\r\n        return new String[]{\"C:\", \"D:\"};\r\n    }\r\n\r\n    /**\r\n     * Receives the pathname denoted by a root folder (for the special case of links...)\r\n     */\r\n    public String getShortRootName(String rootFolder) {\r\n        return rootFolder;\r\n    }\r\n\r\n    /**\r\n     * Called to initiatilize a file transfer\r\n     */\r\n    public String initiateTransfer(String files[], boolean push) {\r\n        count = 0;\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Called in order to interrogate on the status of the current transfer\r\n     */\r\n    public double getTransferPercent() {\r\n        count += 10;\r\n        return count;\r\n    }\r\n\r\n} // end of class DummyRemoteSessionManager\r\n\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/EnhancedJPanel.java",
    "content": "/*\n * $Id: EnhancedJPanel.java 350 2007-08-16 14:11:38Z ramiro $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport java.awt.*;\n\n/**\n * @author Ciprian Dobre\n */\npublic class EnhancedJPanel extends JPanel {\n\n    private static final Color transparent = new Color(255, 255, 255);\n\n    //\tprivate static final Color lightBlue = new Color(130, 200, 250);\n    private static final Color lightBlue = new Color(210, 237, 255);\n\n    private static final Color selectedColor = new Color(184, 208, 224);\n\n    public void paintComponent(Graphics g) {\n\n        GradientPaint leftGradient;\n        GradientPaint rightGradient;\n\n        Dimension d = getSize();\n\n        if (d == null) return;\n\n        leftGradient = new GradientPaint(0, 0, selectedColor,\n                (int) d.getWidth() / 2, 0, lightBlue);\n\n        rightGradient = new GradientPaint((int) d.getWidth() / 2, 0, lightBlue, (int) d.getWidth(), 0, transparent);\n\n        Graphics2D g2 = (Graphics2D) g;\n        g2.setPaint(leftGradient);\n        g2.fillRect(0, 0, (int) d.getWidth() / 2, (int) d.getHeight());\n        g2.setPaint(rightGradient);\n        g2.fillRect((int) d.getWidth() / 2, 0, (int) d.getWidth(), (int) d.getHeight());\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/FDTPropsDialog.java",
    "content": "/*\n * $Id: FDTPropsDialog.java 378 2007-08-20 17:57:34Z ramiro $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.*;\nimport java.text.NumberFormat;\n\n/**\n * @author Ciprian Dobre\n */\npublic class FDTPropsDialog extends JDialog implements KeyListener {\n\n    private static final NumberFormat nf = NumberFormat.getInstance();\n\n    static {\n        nf.setMaximumFractionDigits(2);\n    }\n\n    final JFrame parent;\n    final JDialog dialog;\n    public boolean bDialogOK = false;\n    /**\n     * The possible values that can be set in this dialog..\n     */\n\n    private int sockBufSize = -1;\n    private int sockNum = 4;\n    private long rateLimit = -1;\n    private int readersCount = 1;\n    private int writersCount = 1;\n    private int maxPartitionsCount = 100;\n    private boolean bComputeMD5 = false;\n    private boolean bUseFixedBlocks = false;\n    private double transferLimit = -1;\n    private JTextField textSockBufSize = new JTextField();\n    private JTextField textSockNum = new JTextField();\n    private JTextField textRateLimit = new JTextField();\n    private JTextField textReadersCount = new JTextField();\n    private JTextField textWritersCount = new JTextField();\n    private JTextField textMaxPartitionsCount = new JTextField();\n    private JTextField textComputeMD5 = new JTextField();\n    private JTextField textTransferLimit = new JTextField();\n\n    public FDTPropsDialog(JFrame f) {\n        super(f, \"Connection preferences\", true);\n\n        dialog = this;\n\n        final JPanel mainPanel = new EnhancedJPanel();\n        mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));\n\n        try {\n            loadPrefs();\n        } catch (Throwable t) {\n        }\n\n        this.parent = f;\n        final JPanel sockBufSizePanel = new JPanel();\n        sockBufSizePanel.setOpaque(false);\n        sockBufSizePanel.setLayout(new BoxLayout(sockBufSizePanel, BoxLayout.X_AXIS));\n        mainPanel.add(sockBufSizePanel);\n        sockBufSizePanel.add(new JLabel(\"SockBufSize: \"));\n        textSockBufSize.setText(\"\" + sockBufSize);\n        textSockBufSize.addKeyListener(this);\n        sockBufSizePanel.add(textSockBufSize);\n\n        final JPanel sockNumPanel = new JPanel();\n        sockNumPanel.setOpaque(false);\n        sockNumPanel.setLayout(new BoxLayout(sockNumPanel, BoxLayout.X_AXIS));\n        mainPanel.add(sockNumPanel);\n        sockNumPanel.add(new JLabel(\"NoOfStreams: \"));\n        textSockNum.setText(\"\" + sockNum);\n        textSockNum.addKeyListener(this);\n        sockNumPanel.add(textSockNum);\n\n        final JPanel transferLimitPanel = new JPanel();\n        transferLimitPanel.setOpaque(false);\n        transferLimitPanel.setLayout(new BoxLayout(transferLimitPanel, BoxLayout.X_AXIS));\n        mainPanel.add(transferLimitPanel);\n        transferLimitPanel.add(new JLabel(\"TransferLimit:\"));\n        textTransferLimit.setText(nf.format(transferLimit));\n        textTransferLimit.addKeyListener(this);\n        transferLimitPanel.add(textTransferLimit);\n\n        final JPanel rateLimitPanel = new JPanel();\n        rateLimitPanel.setOpaque(false);\n        rateLimitPanel.setLayout(new BoxLayout(rateLimitPanel, BoxLayout.X_AXIS));\n        rateLimitPanel.add(new JLabel(\"RateLimit: \"));\n        textRateLimit.setText(\"\" + rateLimit);\n        textRateLimit.addKeyListener(this);\n        rateLimitPanel.add(textRateLimit);\n\n        final JPanel readersCountPanel = new JPanel();\n        readersCountPanel.setOpaque(false);\n        readersCountPanel.setLayout(new BoxLayout(readersCountPanel, BoxLayout.X_AXIS));\n        readersCountPanel.add(new JLabel(\"ReadersCount:\"));\n        textReadersCount.setText(\"\" + readersCount);\n        textReadersCount.addKeyListener(this);\n        readersCountPanel.add(textReadersCount);\n\n        final JPanel writersCountPanel = new JPanel();\n        writersCountPanel.setOpaque(false);\n        writersCountPanel.setLayout(new BoxLayout(writersCountPanel, BoxLayout.X_AXIS));\n        writersCountPanel.add(new JLabel(\"WritersCount:\"));\n        textWritersCount.setText(\"\" + writersCount);\n        textWritersCount.addKeyListener(this);\n        writersCountPanel.add(textWritersCount);\n\n        final JPanel maxPartitionsPanel = new JPanel();\n        maxPartitionsPanel.setOpaque(false);\n        maxPartitionsPanel.setLayout(new BoxLayout(maxPartitionsPanel, BoxLayout.X_AXIS));\n        maxPartitionsPanel.add(new JLabel(\"MaxPartitionsCount:\"));\n        textMaxPartitionsCount.setText(\"\" + maxPartitionsCount);\n        textMaxPartitionsCount.addKeyListener(this);\n        maxPartitionsPanel.add(textMaxPartitionsCount);\n\n        final JPanel computeMD5Panel = new JPanel();\n        computeMD5Panel.setOpaque(false);\n        computeMD5Panel.setLayout(new BoxLayout(computeMD5Panel, BoxLayout.X_AXIS));\n        computeMD5Panel.add(new JLabel(\"ComputeMD5:\"));\n        textComputeMD5.setText(\"\" + bComputeMD5);\n        textComputeMD5.addKeyListener(this);\n        computeMD5Panel.add(textComputeMD5);\n\n        final JPanel advancedPanel = new JPanel();\n        advancedPanel.setOpaque(false);\n        advancedPanel.setLayout(new BorderLayout());\n        mainPanel.add(advancedPanel);\n        final JButton advanced = new JButton(\"Advanced options\");\n        advancedPanel.add(advanced);\n\n        final JPanel buttonPanel = new JPanel();\n        buttonPanel.setOpaque(false);\n        buttonPanel.setLayout(new GridLayout(0, 2));\n        mainPanel.add(buttonPanel);\n        JButton bOK = new JButton(\"OK\");\n        bOK.addKeyListener(this);\n        bOK.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent arg0) {\n                if (!checkParams())\n                    return;\n                bDialogOK = true;\n                setVisible(false);\n            }\n        });\n        buttonPanel.add(bOK);\n        JButton bCancel = new JButton(\"Cancel\");\n        bCancel.addKeyListener(this);\n        bCancel.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent arg0) {\n                bDialogOK = false;\n                setVisible(false);\n            }\n        });\n        buttonPanel.add(bCancel);\n\n        advanced.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                if (advanced.getText().equals(\"Advanced options\")) {\n                    advanced.setText(\"Basic options\");\n                    mainPanel.remove(advancedPanel);\n                    mainPanel.remove(buttonPanel);\n                    mainPanel.add(rateLimitPanel);\n                    mainPanel.add(readersCountPanel);\n                    mainPanel.add(writersCountPanel);\n                    mainPanel.add(maxPartitionsPanel);\n                    mainPanel.add(computeMD5Panel);\n                    mainPanel.add(advancedPanel);\n                    mainPanel.add(buttonPanel);\n                    dialog.pack();\n                } else {\n                    advanced.setText(\"Advanced options\");\n                    mainPanel.remove(rateLimitPanel);\n                    mainPanel.remove(readersCountPanel);\n                    mainPanel.remove(writersCountPanel);\n                    mainPanel.remove(maxPartitionsPanel);\n                    mainPanel.remove(computeMD5Panel);\n                    dialog.pack();\n                }\n            }\n        });\n\n        getContentPane().setLayout(new BorderLayout(2, 2));\n        getContentPane().add(mainPanel, BorderLayout.CENTER);\n        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);\n        setSize(330, 330);\n        setLocationRelativeTo(parent);\n        pack();\n    }\n\n    private final boolean checkParams() {\n\n        int tmpSockBufSize = sockBufSize;\n        int tmpSockNum = sockNum;\n        long tmpRateLimit = rateLimit;\n        int tmpReadersCount = readersCount;\n        int tmpWritersCount = writersCount;\n        int tmpMaxPartitionsCount = maxPartitionsCount;\n        boolean tmpBComputeMD5 = bComputeMD5;\n        double tmpTransferLimit = transferLimit;\n\n        String s = textSockBufSize.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpSockBufSize = Integer.parseInt(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for SockBufSize\");\n                return false;\n            }\n        }\n        s = textSockNum.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpSockNum = Integer.parseInt(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for NoOfStreams\");\n                return false;\n            }\n        }\n        s = textRateLimit.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpRateLimit = Long.parseLong(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for RateLimit\");\n                return false;\n            }\n        }\n        s = textReadersCount.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpReadersCount = Integer.parseInt(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for ReadersCount\");\n                return false;\n            }\n        }\n        s = textWritersCount.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpWritersCount = Integer.parseInt(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for WritersCount\");\n                return false;\n            }\n        }\n        s = textMaxPartitionsCount.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpMaxPartitionsCount = Integer.parseInt(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for MaxPartitionsCount\");\n                return false;\n            }\n        }\n        s = textComputeMD5.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpBComputeMD5 = Boolean.valueOf(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must entera vald value for ComputeMD5\");\n                return false;\n            }\n        }\n        s = textTransferLimit.getText();\n        if (s != null && s.length() != 0) {\n            try {\n                tmpTransferLimit = Double.valueOf(s);\n            } catch (Exception e) {\n                JOptionPane.showMessageDialog(parent, \"You must enter a valid value for TransferLimit\");\n                return false;\n            }\n        }\n\n        sockBufSize = tmpSockBufSize;\n        sockNum = tmpSockNum;\n        rateLimit = tmpRateLimit;\n        readersCount = tmpReadersCount;\n        writersCount = tmpWritersCount;\n        maxPartitionsCount = tmpMaxPartitionsCount;\n        bComputeMD5 = tmpBComputeMD5;\n        transferLimit = tmpTransferLimit;\n        savePrefs();\n        return true;\n    }\n\n    private final void loadPrefs() {\n        String s = PreferencesHandler.get(\"sockBufSize\", \"\" + sockBufSize);\n        try {\n            sockBufSize = Integer.parseInt(s);\n        } catch (Exception e) {\n        }\n        s = PreferencesHandler.get(\"sockNum\", \"\" + sockNum);\n        try {\n            sockNum = Integer.parseInt(s);\n        } catch (Exception e) {\n        }\n        s = PreferencesHandler.get(\"rateLimit\", \"\" + rateLimit);\n        try {\n            rateLimit = Long.parseLong(s);\n        } catch (Exception e) {\n        }\n        s = PreferencesHandler.get(\"readersCount\", \"\" + readersCount);\n        try {\n            readersCount = Integer.parseInt(s);\n        } catch (Exception e) {\n        }\n        s = PreferencesHandler.get(\"writersCount\", \"\" + writersCount);\n        try {\n            writersCount = Integer.parseInt(s);\n        } catch (Exception e) {\n        }\n        s = PreferencesHandler.get(\"maxPartitionsCount\", \"\" + maxPartitionsCount);\n        try {\n            maxPartitionsCount = Integer.parseInt(s);\n        } catch (Exception e) {\n        }\n        bComputeMD5 = PreferencesHandler.getBoolean(\"computeMD5\", bComputeMD5);\n        s = PreferencesHandler.get(\"transferLimit\", nf.format(transferLimit));\n        try {\n            transferLimit = Double.parseDouble(s);\n        } catch (Exception e) {\n        }\n    }\n\n    private final void savePrefs() {\n        PreferencesHandler.put(\"sockBufSize\", \"\" + sockBufSize);\n        PreferencesHandler.put(\"sockNum\", \"\" + sockNum);\n        PreferencesHandler.put(\"rateLimit\", \"\" + rateLimit);\n        PreferencesHandler.put(\"readersCount\", \"\" + readersCount);\n        PreferencesHandler.put(\"writersCount\", \"\" + writersCount);\n        PreferencesHandler.put(\"maxPartitionsCount\", \"\" + maxPartitionsCount);\n        PreferencesHandler.putBoolean(\"computeMD5\", bComputeMD5);\n        PreferencesHandler.put(\"transferLimit\", nf.format(transferLimit));\n        PreferencesHandler.save();\n    }\n\n    public void keyTyped(KeyEvent e) {\n    }\n\n    public void keyPressed(KeyEvent e) {\n    }\n\n    public void keyReleased(KeyEvent e) {\n        if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {\n            bDialogOK = false;\n            setVisible(false);\n            return;\n        }\n        if (e.getKeyCode() == KeyEvent.VK_ENTER) {\n            if (!checkParams())\n                return;\n            bDialogOK = true;\n            setVisible(false);\n            return;\n        }\n    }\n\n    public void setVisible(boolean v) {\n        if (v) {\n            setLocationRelativeTo(parent);\n            pack();\n        }\n        super.setVisible(v);\n    }\n\n    public boolean isBComputeMD5() {\n        return bComputeMD5;\n    }\n\n    public boolean isBUseFixedBlocks() {\n        return bUseFixedBlocks;\n    }\n\n    public int getMaxPartitionsCount() {\n        return maxPartitionsCount;\n    }\n\n    public long getRateLimit() {\n        return rateLimit;\n    }\n\n    public int getReadersCount() {\n        return readersCount;\n    }\n\n    public int getSockNum() {\n        return sockNum;\n    }\n\n    public int getSockBufSize() {\n        return sockBufSize;\n    }\n\n    public double getTransferLimit() {\n        return transferLimit;\n    }\n\n    public int getWritersCount() {\n        return writersCount;\n    }\n\n} // end of class FDTPropsDialog\n\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/FolderFrame.java",
    "content": "/*\r\n * $Id: FolderFrame.java 474 2007-10-11 11:38:24Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui;\r\n\r\nimport lia.util.net.copy.gui.session.LocalSession;\r\nimport lia.util.net.copy.gui.session.RemoteSession;\r\n\r\nimport javax.swing.*;\r\nimport java.awt.*;\r\nimport java.awt.event.*;\r\nimport java.net.URL;\r\nimport java.util.Enumeration;\r\nimport java.util.logging.LogManager;\r\n\r\n/**\r\n * The Panel showing files and folders\r\n * It is dirrectly linked to a Session (can be local or remote)\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class FolderFrame extends JFrame implements ActionListener, FocusListener {\r\n\r\n    public FolderTable local;\r\n    public FolderTable remote;\r\n\r\n    public JMenu localMenu;\r\n    public JMenu remoteMenu;\r\n    public JMenu command;\r\n    protected JMenuItem aboutItem;\r\n    protected JMenuItem helpItem;\r\n    protected JMenuItem connectItem;\r\n    protected JMenuItem propsItem;\r\n    protected StatusBar statusBar;\r\n    ConnectDialog connect;\r\n    RemoteSessionManager manager;\r\n    ImageIcon prefsIcon;\r\n    ImageIcon connIcon;\r\n    ImageIcon leftIcon;\r\n    ImageIcon rightIcon;\r\n    ImageIcon mkdirIcon;\r\n    ImageIcon removeIcon;\r\n    ImageIcon indexIcon;\r\n    private AboutDialog about;\r\n    private HelpDialog help;\r\n    private FDTPropsDialog props;\r\n    private JButton copyLeft;\r\n    private JButton copyRight;\r\n    private ImageIcon fdtIcon;\r\n\r\n    public FolderFrame() {\r\n        super(\"Fast Data Transfer\");\r\n\r\n        props = new FDTPropsDialog(this);\r\n        propsItem = new JMenuItem(\"Preferences\");\r\n        propsItem.setIcon(getPrefsIcon());\r\n        propsItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent e) {\r\n                props.setVisible(true);\r\n                props.toFront();\r\n            }\r\n        });\r\n        JPanel panel = new JPanel();\r\n        this.manager = new RemoteSessionManager(props, panel);\r\n\r\n        connect = new ConnectDialog(this);\r\n        manager.initiated = true;\r\n\r\n        panel.setOpaque(false);\r\n        panel.setLayout(new BorderLayout());\r\n        JPanel pp = new JPanel();\r\n        JScrollPane p1 = new JScrollPane(pp);\r\n        statusBar = new StatusBar(p1);\r\n        pp.setOpaque(true);\r\n        pp.setBackground(Color.white);\r\n        pp.setLayout(new BorderLayout());\r\n        pp.add(statusBar, BorderLayout.CENTER);\r\n        p1.setOpaque(false);\r\n        p1.setMinimumSize(new Dimension(5, 20));\r\n        p1.setPreferredSize(new Dimension(5, 20));\r\n\r\n        CustomPrintStream out = new CustomPrintStream(statusBar, System.out, \"#000000\");\r\n        System.setOut(out);\r\n        CustomPrintStream err = new CustomPrintStream(statusBar, System.err, \"#ff0000\");\r\n        System.setErr(err);\r\n\r\n        CustomLogHandler logHandler = new CustomLogHandler(statusBar);\r\n        for (Enumeration<String> en = LogManager.getLogManager().getLoggerNames(); en.hasMoreElements(); ) {\r\n            String logName = en.nextElement();\r\n            LogManager.getLogManager().getLogger(logName).addHandler(logHandler);\r\n        }\r\n\r\n        JPanel p = new JPanel();\r\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\r\n\r\n        LocalSession localSession = new LocalSession();\r\n        local = new FolderTable(localSession, manager, statusBar, this);\r\n        JPanel left = createPanel(local);\r\n        localMenu = new JMenu(\"Local\");\r\n        localMenu.add(local.visibleColumns);\r\n        command = local.command;\r\n        command.add(propsItem, 1);\r\n\r\n        final RemoteSession session = new RemoteSession(manager);\r\n        remote = new FolderTable(session, manager, statusBar, this);\r\n        JPanel right = createPanel(remote);\r\n        remoteMenu = new JMenu(\"Remote\");\r\n        remoteMenu.add(remote.visibleColumns);\r\n        connectItem = new JMenuItem(\"Connect\");\r\n        connectItem.setIcon(getConnIcon());\r\n        connectItem.addActionListener(this);\r\n        remoteMenu.add(connectItem);\r\n        manager.setCorrespondingPanel(local, remote);\r\n\r\n        JPanel middle = new JPanel();\r\n        middle.setLayout(new GridLayout(0, 1));\r\n        middle.setOpaque(false);\r\n        copyLeft = new JButton(getLeftIcon());\r\n        copyLeft.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        remote.copy();\r\n                    }\r\n                };\r\n                local.exec.execute(r);\r\n            }\r\n        });\r\n        copyLeft.setFocusable(false);\r\n        copyLeft.setMaximumSize(new Dimension(24, 24));\r\n        copyLeft.setPreferredSize(new Dimension(24, 24));\r\n        copyLeft.setToolTipText(\"Copy\");\r\n        copyLeft.setEnabled(false);\r\n        middle.add(copyLeft);\r\n\r\n        copyRight = new JButton(getRightIcon());\r\n        copyRight.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        local.copy();\r\n                    }\r\n                };\r\n                local.exec.execute(r);\r\n            }\r\n        });\r\n        copyRight.setFocusable(false);\r\n        copyRight.setMaximumSize(new Dimension(24, 24));\r\n        copyRight.setPreferredSize(new Dimension(24, 24));\r\n        copyRight.setToolTipText(\"Copy\");\r\n        copyRight.setEnabled(false);\r\n        middle.add(copyRight);\r\n\r\n        middle.setMaximumSize(new Dimension(24, 72));\r\n        middle.setPreferredSize(new Dimension(24, 72));\r\n\r\n        JPanel pp1 = new JPanel();\r\n        pp1.setOpaque(false);\r\n        pp1.setLayout(new BoxLayout(pp1, BoxLayout.X_AXIS));\r\n        pp1.setMaximumSize(new Dimension(24, 72));\r\n        pp1.setPreferredSize(new Dimension(24, 72));\r\n\r\n        pp1.add(middle);\r\n\r\n        p.add(left);\r\n        p.add(pp1);\r\n        p.add(right);\r\n\r\n        manager.setSessions(localSession, session);\r\n\r\n        JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, p, p1);\r\n        splitPane.setOneTouchExpandable(true);\r\n        splitPane.setContinuousLayout(true);\r\n        splitPane.setResizeWeight(1.0);\r\n        panel.add(splitPane, BorderLayout.CENTER);\r\n\r\n        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();\r\n        setSize((int) dim.getWidth(), (int) dim.getHeight() - 30);\r\n        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r\n        getContentPane().setLayout(new BorderLayout());\r\n        getContentPane().add(panel, BorderLayout.CENTER);\r\n        JMenuBar menu = new JMenuBar();\r\n        menu.add(localMenu);\r\n        menu.add(command);\r\n        menu.add(remoteMenu);\r\n        setJMenuBar(menu);\r\n        setIconImage(getFDTIcon().getImage());\r\n        about = new AboutDialog(this);\r\n        JMenu h = new JMenu(\"Help\");\r\n        aboutItem = new JMenuItem(\"About\");\r\n        aboutItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent e) {\r\n                about.setVisible(true);\r\n            }\r\n        });\r\n        h.add(aboutItem);\r\n        help = new HelpDialog(this);\r\n        helpItem = new JMenuItem(\"Key mappings\");\r\n        helpItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent e) {\r\n                help.setVisible(true);\r\n            }\r\n        });\r\n        h.add(helpItem);\r\n        menu.add(h);\r\n        local.getTable().requestFocusInWindow();\r\n    }\r\n\r\n    public static void main(String args[]) {\r\n        FolderFrame panel = new FolderFrame();\r\n        panel.setVisible(true);\r\n        panel.toFront();\r\n\r\n//\t\tfor (int i=0; i<10000; i++) {\r\n//\t\t\tpanel.statusBar.addText(\"ttttttr\\n\");\r\n//\t\t\ttry { Thread.sleep(100); } catch (Throwable t) { }\r\n//\t\t}\r\n    }\r\n\r\n    private Icon getPrefsIcon() {\r\n        if (prefsIcon != null) return prefsIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/preferences.png\");\r\n            prefsIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return prefsIcon;\r\n    }\r\n\r\n    private Icon getConnIcon() {\r\n        if (connIcon != null) return connIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/connect.gif\");\r\n            connIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return connIcon;\r\n    }\r\n\r\n    private final JPanel createPanel(FolderTable table) {\r\n        JPanel left = new JPanel();\r\n        left.setOpaque(false);\r\n        left.setLayout(new BorderLayout());\r\n        JPanel p = new JPanel();\r\n        p.setOpaque(false);\r\n        p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));\r\n        p.add(table.roots);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.refreshDir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.parentDir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.rootDir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.homeDir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.openDir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.separator);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.mkdir);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.remove);\r\n        p.add(Box.createHorizontalStrut(5));\r\n        p.add(table.freeSpace);\r\n\r\n        p.add(Box.createHorizontalGlue());\r\n        left.add(p, BorderLayout.NORTH);\r\n        left.add(table, BorderLayout.CENTER);\r\n        left.setBorder(BorderFactory.createLoweredBevelBorder());\r\n        return left;\r\n    }\r\n\r\n    private ImageIcon getFDTIcon() {\r\n        if (fdtIcon != null) return fdtIcon;\r\n        try {\r\n            URL url = getClass().getResource(\"icons/fdt.png\");\r\n            fdtIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return fdtIcon;\r\n    }\r\n\r\n    public void actionPerformed(ActionEvent e) { // connect called...\r\n        connect.setVisible(true);\r\n        connect.toFront();\r\n        if (connect.bDialogOK) {\r\n            manager.initiated = false;\r\n            int port = 54321;\r\n            try {\r\n                port = Integer.valueOf(connect.sPort);\r\n            } catch (Throwable t) {\r\n            }\r\n            manager.connect(connect.sHost, connect.sUser, port);\r\n        } else {\r\n            manager.initiated = true;\r\n        }\r\n    }\r\n\r\n    public void focusGained(FocusEvent e) {\r\n        if (local.getTable().hasFocus()) {\r\n            local.showSelection();\r\n            remote.hideSelection();\r\n            copyRight.setEnabled(true);\r\n            copyLeft.setEnabled(false);\r\n            local.scroll.getViewport().setBackground(FolderTable.cm);\r\n            remote.scroll.getViewport().setBackground(FolderTable.cg);\r\n        } else if (remote.getTable().hasFocus()) {\r\n            remote.showSelection();\r\n            local.hideSelection();\r\n            copyRight.setEnabled(false);\r\n            copyLeft.setEnabled(true);\r\n            local.scroll.getViewport().setBackground(FolderTable.cg);\r\n            remote.scroll.getViewport().setBackground(FolderTable.cm);\r\n        }\r\n    }\r\n\r\n    public void focusLost(FocusEvent e) {\r\n        copyLeft.setEnabled(false);\r\n        copyRight.setEnabled(false);\r\n//\t\tlocal.scroll.getViewport().setBackground(FolderTable.cg);\r\n//\t\tremote.scroll.getViewport().setBackground(FolderTable.cg);\r\n    }\r\n\r\n    private Icon getLeftIcon() {\r\n        if (leftIcon != null) return leftIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/left.png\");\r\n            leftIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return leftIcon;\r\n    }\r\n\r\n    private Icon getRightIcon() {\r\n        if (rightIcon != null) return rightIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/right.png\");\r\n            rightIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return rightIcon;\r\n    }\r\n\r\n    private Icon getMkDirIcon() {\r\n        if (mkdirIcon != null) return mkdirIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/mkdir.png\");\r\n            mkdirIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return mkdirIcon;\r\n    }\r\n\r\n    private Icon getRemoveIcon() {\r\n        if (removeIcon != null) return removeIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/delete.png\");\r\n            removeIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return removeIcon;\r\n    }\r\n\r\n    private Icon getIndexIcon() {\r\n        if (indexIcon != null) return indexIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/index.png\");\r\n            indexIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return indexIcon;\r\n    }\r\n\r\n\r\n}\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/FolderTable.java",
    "content": "/*\r\n * $Id: FolderTable.java 530 2009-06-04 13:38:13Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui;\r\n\r\nimport lia.util.net.copy.gui.session.LocalSession;\r\nimport lia.util.net.copy.gui.session.Session;\r\n\r\nimport javax.swing.*;\r\nimport javax.swing.border.*;\r\nimport javax.swing.table.*;\r\nimport java.awt.*;\r\nimport java.awt.event.*;\r\nimport java.net.URL;\r\nimport java.text.NumberFormat;\r\nimport java.text.SimpleDateFormat;\r\nimport java.util.*;\r\nimport java.util.concurrent.ExecutorService;\r\nimport java.util.concurrent.Executors;\r\n\r\n/**\r\n * Represents the folder data into a JTable\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class FolderTable extends JPanel {\r\n\r\n    public static final Color cg = new Color(217, 217, 217);\r\n    public static final Color cm = (new JPanel()).getBackground();\r\n    final static ExecutorService exec = Executors.newCachedThreadPool();\r\n    private final static String colNames[] = new String[]{\"Icon\", \"Name\", \"Modified\", \"Size\", \"##\"};\r\n    private static final SimpleDateFormat dateFormat = new SimpleDateFormat(\"dd.MM.yy HH:mm:ss\");\r\n    private static final NumberFormat nf = NumberFormat.getInstance(Locale.US);\r\n    private static final Color c1 = new Color(128, 179, 230);\r\n    private static final Color c2 = new Color(220, 234, 248);\r\n    private static final Color c22 = new Color(226, 241, 255);\r\n    private static final Color c3 = new Color(200, 200, 200);\r\n    private static final Color c4 = new Color(245, 255, 255);\r\n    private static final Color c44 = new Color(255, 255, 255);\r\n    public static TransferMonitor transferMonitor = null;\r\n\r\n    static {\r\n        nf.setMaximumFractionDigits(2);\r\n    }\r\n\r\n    final FolderTable ft;\r\n    private final Vector<String> columns = new Vector<String>();\r\n    private final String pack = \"/\" + getClass().getPackage().getName().replace(\".\", \"/\");\r\n    private final StatusBar statusBar;\r\n    private final Vector<FileHandler> rows = new Vector<FileHandler>();\r\n    private final MyTableHeaderRenderer headerRenderer = new MyTableHeaderRenderer();\r\n    private final MyTableCellRenderer cellRenderer = new MyTableCellRenderer();\r\n    private final RemoteSessionManager manager;\r\n    public JComboBox roots;\r\n    public JLabel freeSpace;\r\n    public JLabel parentDir;\r\n    public JLabel rootDir;\r\n    public JLabel homeDir;\r\n    public JLabel refreshDir;\r\n    public JLabel openDir;\r\n    public JLabel separator;\r\n    public JLabel mkdir;\r\n    public JLabel remove;\r\n    public JMenu visibleColumns;\r\n    public JMenu command;\r\n    public JScrollPane scroll;\r\n    public Session session;\r\n    long lastTimeKeyPressed = System.currentTimeMillis();\r\n    String currentKeys = \"\";\r\n    ImageIcon upDirIcon;\r\n    ImageIcon rootIcon;\r\n    ImageIcon copyIcon;\r\n    ImageIcon exitIcon;\r\n    ImageIcon openDirIcon;\r\n    ImageIcon refreshIcon;\r\n    ImageIcon openHomeIcon;\r\n    ImageIcon selectIcon;\r\n    ImageIcon sortAIcon;\r\n    ImageIcon sortDIcon;\r\n    ImageIcon mkdirIcon;\r\n    ImageIcon removeIcon;\r\n    ImageIcon connIcon;\r\n    ImageIcon verticalIcon;\r\n    private JTable table;\r\n    private JPopupMenu popup;\r\n    private boolean showIcon = true;\r\n    private boolean showLength = true;\r\n    private boolean showModif = true;\r\n    private boolean showAttrib = true;\r\n    private String sortColumn = \"Name\";\r\n    private boolean sortAsc = true;\r\n    private JMenuItem showIconItem;\r\n    private JMenuItem showLengthItem;\r\n    private JMenuItem showModifItem;\r\n    private JMenuItem showAttribItem;\r\n    private JMenuItem copy;\r\n    private JMenuItem exit;\r\n    private JPanel connectPanel;\r\n    private JPanel tablePanel;\r\n    private boolean showSelection = true;\r\n    private String currentDir = null;\r\n    private String lastDir = null;\r\n    private String selectedDir = null;\r\n    private FolderFrame frame;\r\n    private long lastClick = 0L;\r\n    private int lastRow = -1;\r\n\r\n    public FolderTable(final Session session, final RemoteSessionManager manager, final StatusBar statusBar, final FolderFrame focusListener) {\r\n        super();\r\n        ft = this;\r\n        this.frame = focusListener;\r\n        this.statusBar = statusBar;\r\n        this.manager = manager;\r\n        this.session = session;\r\n\r\n        popup = createPopup();\r\n\r\n        tablePanel = new JPanel();\r\n        tablePanel.setLayout(new BorderLayout());\r\n        tablePanel.setOpaque(false);\r\n\r\n        setLayout(new BorderLayout());\r\n        MyTableModel model = new MyTableModel();\r\n        table = new JTable(model);\r\n        table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);\r\n        table.setIntercellSpacing(new Dimension(0, 0));\r\n        JTableHeader header = table.getTableHeader();\r\n        header.addMouseListener(new ColumnHeaderListener());\r\n        MouseListener mouseListener = new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                if (((e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0)) {\r\n                    table.requestFocusInWindow();\r\n                    if (!isDoubleClick(e)) return;\r\n                    int row = table.getSelectedRow();\r\n                    if (row < 0 || row >= rows.size()) return;\r\n                    // get the corresponding row in the table\r\n                    final FileHandler fh = rows.get(row);\r\n                    if (fh.getSizeL() > 0) // clicked on a normal file\r\n                        return;\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            ft.setEnabled(false);\r\n//\t    \t\t\t\t\tremoveCurrentDir();\r\n                            try {\r\n                                if (fh.getName().equals(\"..\")) {\r\n                                    lastDir = session.getWorkingDir();\r\n                                    if (lastDir.contains(session.getFileSeparator()))\r\n                                        lastDir = lastDir.substring(lastDir.lastIndexOf(session.getFileSeparator()) + 1);\r\n                                    session.setUpDir();\r\n                                } else\r\n                                    session.setRelativeDir(fh.getName());\r\n                            } catch (Throwable t) {\r\n                                // unhandled exception\r\n                            }\r\n                            updateTable();\r\n                            ft.setEnabled(true);\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                if (((e.getModifiers() & MouseEvent.BUTTON3_MASK) != 0)) {\r\n                    table.requestFocusInWindow();\r\n                    popup.show(e.getComponent(), e.getX(), e.getY());\r\n                    table.requestFocusInWindow();\r\n                    return;\r\n                }\r\n            }\r\n        };\r\n        table.addMouseListener(mouseListener);\r\n        table.addFocusListener(focusListener);\r\n        table.addKeyListener(new KeyAdapter() {\r\n            public void keyPressed(KeyEvent e) {\r\n                int key = e.getKeyCode();\r\n                if (key == KeyEvent.VK_ENTER) {\r\n                    if (table.getSelectedRowCount() > 1) {\r\n                        setStatus(\"Unable to cd... more than one files selected\");\r\n                        return;\r\n                    }\r\n                    int row = table.getSelectedRow();\r\n                    if (row < 0 || row >= rows.size()) return;\r\n                    // get the corresponding row in the table\r\n                    final FileHandler fh = rows.get(row);\r\n                    if (fh.getSizeL() > 0) { // clicked on a normal file\r\n                        setStatus(\"Unable to cd... normal file selected\");\r\n                        return;\r\n                    }\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            ft.setEnabled(false);\r\n//\t    \t\t\t\t\tremoveCurrentDir();\r\n                            if (fh.getName().equals(\"..\")) {\r\n                                lastDir = session.getWorkingDir();\r\n                                if (lastDir.contains(session.getFileSeparator()))\r\n                                    lastDir = lastDir.substring(lastDir.lastIndexOf(session.getFileSeparator()) + 1);\r\n                                try {\r\n                                    session.setUpDir();\r\n                                } catch (Exception e) {\r\n                                    JOptionPane.showMessageDialog(ft, e.toString());\r\n                                }\r\n                            } else {\r\n                                try {\r\n                                    session.setRelativeDir(fh.getName());\r\n                                } catch (Exception e) {\r\n                                    JOptionPane.showMessageDialog(ft, e.toString());\r\n                                }\r\n                            }\r\n                            updateTable();\r\n                            ft.setEnabled(true);\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                if (key == KeyEvent.VK_F5) {\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            copy();\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                if (key == KeyEvent.VK_F7) {\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            makeDir();\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                if (key == KeyEvent.VK_F8 || key == KeyEvent.VK_DELETE) {\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            removeFiles();\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                if (key == KeyEvent.VK_F10) {\r\n                    System.exit(0);\r\n                }\r\n                if (key == KeyEvent.VK_TAB) {\r\n                    if (command == null) { // remote session\r\n                        if (manager.getLocalTable().table != null)\r\n                            manager.getLocalTable().table.requestFocusInWindow();\r\n                    } else {\r\n                        if (manager.getRemoteTable().table != null)\r\n                            manager.getRemoteTable().table.requestFocusInWindow();\r\n                    }\r\n                    e.consume();\r\n                    return;\r\n                }\r\n                char c = e.getKeyChar();\r\n                if (Character.isDefined(c)) {\r\n                    long now = System.currentTimeMillis();\r\n                    if ((now - lastTimeKeyPressed) < 1300) {\r\n                        currentKeys += c;\r\n                    } else {\r\n                        currentKeys = \"\" + c;\r\n                    }\r\n                    lastTimeKeyPressed = now;\r\n                    selectStartWith(currentKeys);\r\n                }\r\n            }\r\n        });\r\n        table.setShowGrid(false);\r\n        table.setShowVerticalLines(false);\r\n        tablePanel.addMouseListener(mouseListener);\r\n        tablePanel.add(table.getTableHeader(), BorderLayout.NORTH);\r\n        scroll = new JScrollPane(table);\r\n        scroll.addMouseListener(mouseListener);\r\n        tablePanel.add(scroll, BorderLayout.CENTER);\r\n        String[] rs = null;\r\n        try {\r\n            rs = session.getRoots();\r\n        } catch (Exception e) {\r\n            rs = new String[0];\r\n            JOptionPane.showMessageDialog(ft, e.toString());\r\n        }\r\n        roots = new JComboBox(rs);\r\n        roots.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                final String root = (String) roots.getSelectedItem();\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        ft.setEnabled(false);\r\n                        table.requestFocusInWindow();\r\n                        try {\r\n                            session.setAbsoluteDir(root);\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        parentDir = new JLabel(\"\");\r\n        parentDir.setIcon(getUpDirIcon());\r\n        parentDir.setToolTipText(\"Parent directory\");\r\n        parentDir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        ft.setEnabled(false);\r\n                        table.requestFocusInWindow();\r\n                        lastDir = session.getWorkingDir();\r\n                        if (lastDir.contains(session.getFileSeparator()))\r\n                            lastDir = lastDir.substring(lastDir.lastIndexOf(session.getFileSeparator()) + 1);\r\n                        try {\r\n                            session.setUpDir();\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        freeSpace = new JLabel(\"\");\r\n        freeSpace.setToolTipText(\"Amount of available space on the current partition\");\r\n\r\n        rootDir = new JLabel(\"\");\r\n        rootDir.setIcon(getRootIcon());\r\n        rootDir.setToolTipText(\"Root directory\");\r\n        rootDir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        String item = ((String) roots.getSelectedItem());\r\n                        if (item == null) return;\r\n                        ft.setEnabled(false);\r\n                        String r = null;\r\n                        if (session.getOSName().toLowerCase(Locale.US).contains(\"linux\"))\r\n                            r = \"/\"; // in linux only something like this could be qualified as root...\r\n                        else\r\n                            r = session.getShortRootName(item);\r\n                        if (r == null) {\r\n                            ft.setEnabled(true);\r\n                            return;\r\n                        }\r\n                        try {\r\n                            session.setAbsoluteDir(r);\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        homeDir = new JLabel(\"\");\r\n        homeDir.setIcon(getHomeIcon());\r\n        homeDir.setToolTipText(\"Open home directory\");\r\n        homeDir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        String userDir = session.getUserDir();\r\n                        if (userDir == null) return;\r\n                        ft.setEnabled(false);\r\n                        try {\r\n                            session.setAbsoluteDir(userDir);\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        openDir = new JLabel(\"\");\r\n        openDir.setIcon(getOpenDirIcon());\r\n        openDir.setToolTipText(\"Open directory\");\r\n        openDir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                final String root = JOptionPane.showInputDialog(roots, \"Open folder:\", session.getWorkingDir());\r\n                if (root == null) return;\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        ft.setEnabled(false);\r\n                        try {\r\n                            session.setAbsoluteDir(root);\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        refreshDir = new JLabel(\"\");\r\n        refreshDir.setIcon(getRefreshIcon());\r\n        refreshDir.setToolTipText(\"Refresh\");\r\n        refreshDir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        ft.setEnabled(false);\r\n                        String[] str = null;\r\n                        try {\r\n                            str = session.getRoots();\r\n                        } catch (Exception e) {\r\n                            str = new String[0];\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        ActionListener listener = null;\r\n                        if (roots.getActionListeners() != null && roots.getActionListeners().length != 0) {\r\n                            listener = roots.getActionListeners()[0];\r\n                            roots.removeActionListener(listener);\r\n                        }\r\n                        roots.removeAllItems();\r\n                        if (str != null)\r\n                            for (int i = 0; i < str.length; i++)\r\n                                roots.addItem(str[i]);\r\n                        if (listener != null)\r\n                            roots.addActionListener(listener);\r\n                        try {\r\n                            session.setAbsoluteDir(session.getWorkingDir());\r\n                        } catch (Exception e) {\r\n                            JOptionPane.showMessageDialog(ft, e.toString());\r\n                        }\r\n                        updateTable();\r\n                        ft.setEnabled(true);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n\r\n        separator = new JLabel(\"\");\r\n        separator.setIcon(getVertIcon());\r\n\r\n        mkdir = new JLabel(\"\");\r\n        mkdir.setIcon(getMkDirIcon());\r\n        mkdir.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        makeDir();\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        mkdir.setToolTipText(\"Create directory\");\r\n\r\n        remove = new JLabel(\"\");\r\n        remove.setIcon(getRemoveIcon());\r\n        remove.addMouseListener(new MouseAdapter() {\r\n            public void mouseClicked(MouseEvent e) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        removeFiles();\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        remove.setToolTipText(\"Delete\");\r\n\r\n        visibleColumns = new JMenu(\"Display columns\");\r\n        showIconItem = new JMenuItem(\"Icon\");\r\n        showIconItem.setIcon(getSelectIcon());\r\n        setSelectedItem(showIconItem, true);\r\n        showIconItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        setShowIcon(!showIcon);\r\n                        if (!showIcon) {\r\n                            showIconItem.setIcon(null);\r\n                            setSelectedItem(showIconItem, false);\r\n                        } else {\r\n                            showIconItem.setIcon(getSelectIcon());\r\n                            setSelectedItem(showIconItem, true);\r\n                        }\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        visibleColumns.add(showIconItem);\r\n        showLengthItem = new JMenuItem(\"Size\");\r\n        showLengthItem.setIcon(getSelectIcon());\r\n        setSelectedItem(showLengthItem, true);\r\n        showLengthItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        setShowLength(!showLength);\r\n                        if (!showLength) {\r\n                            showLengthItem.setIcon(null);\r\n                            setSelectedItem(showLengthItem, false);\r\n                        } else {\r\n                            showLengthItem.setIcon(getSelectIcon());\r\n                            setSelectedItem(showLengthItem, true);\r\n                        }\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        visibleColumns.add(showLengthItem);\r\n        showModifItem = new JMenuItem(\"Modified\");\r\n        showModifItem.setIcon(getSelectIcon());\r\n        setSelectedItem(showModifItem, true);\r\n        showModifItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        setShowModif(!showModif);\r\n                        if (!showModif) {\r\n                            showModifItem.setIcon(null);\r\n                            setSelectedItem(showModifItem, false);\r\n                        } else {\r\n                            showModifItem.setIcon(getSelectIcon());\r\n                            setSelectedItem(showModifItem, true);\r\n                        }\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        visibleColumns.add(showModifItem);\r\n        showAttribItem = new JMenuItem(\"Attributes\");\r\n        showAttribItem.setIcon(getSelectIcon());\r\n        setSelectedItem(showAttribItem, true);\r\n        showAttribItem.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        table.requestFocusInWindow();\r\n                        setShowAttrib(!showAttrib);\r\n                        if (!showAttrib) {\r\n                            showAttribItem.setIcon(null);\r\n                            setSelectedItem(showAttribItem, false);\r\n                        } else {\r\n                            showAttribItem.setIcon(getSelectIcon());\r\n                            setSelectedItem(showAttribItem, true);\r\n                        }\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        visibleColumns.add(showAttribItem);\r\n\r\n        if (session instanceof LocalSession) {\r\n            command = new JMenu(\"Command\");\r\n            copy = new JMenuItem(\"F5 Copy\");\r\n            copy.setIcon(getCopyIcon());\r\n            copy.addActionListener(new ActionListener() {\r\n                public void actionPerformed(ActionEvent arg0) {\r\n                    Runnable r = new Runnable() {\r\n                        public void run() {\r\n                            copy();\r\n                        }\r\n                    };\r\n                    exec.execute(r);\r\n\r\n                }\r\n            });\r\n            command.add(copy);\r\n            exit = new JMenuItem(\"F10 Exit\");\r\n            exit.setIcon(getExitIcon());\r\n            exit.addActionListener(new ActionListener() {\r\n                public void actionPerformed(ActionEvent arg0) {\r\n                    System.exit(0);\r\n                }\r\n            });\r\n            command.addSeparator();\r\n            command.add(exit);\r\n            updateTable();\r\n        }\r\n\r\n        updateColumns();\r\n\r\n        createConnectPanel();\r\n\r\n        if (session instanceof LocalSession) {\r\n            add(tablePanel, BorderLayout.CENTER);\r\n        } else {\r\n            setConnected(false);\r\n        }\r\n    }\r\n\r\n    private void removeCurrentDir() {\r\n        if (currentDir != null) {\r\n            ActionListener listener = null;\r\n            if (roots.getActionListeners() != null && roots.getActionListeners().length != 0) {\r\n                listener = roots.getActionListeners()[0];\r\n                roots.removeActionListener(listener);\r\n            }\r\n            for (int i = 0; i < roots.getItemCount(); i++) {\r\n                if (roots.getItemAt(i).toString().equals(currentDir)) {\r\n                    roots.removeItemAt(i);\r\n                    break;\r\n                }\r\n            }\r\n            if (listener != null)\r\n                roots.addActionListener(listener);\r\n            currentDir = null;\r\n        }\r\n    }\r\n\r\n    private final boolean isDoubleClick(MouseEvent e) {\r\n        int row = table.getSelectedRow();\r\n        if (table.getSelectedRowCount() > 1) return false;\r\n        if (e.getClickCount() >= 2) {\r\n            lastClick = 0L;\r\n            lastRow = row;\r\n            return true;\r\n        }\r\n        if (lastClick > 0L) {\r\n            long diff = System.currentTimeMillis() - lastClick;\r\n            if (diff < 500L) {\r\n                lastClick = 0L;\r\n                boolean ret = row == lastRow;\r\n                lastRow = row;\r\n                return ret;\r\n            }\r\n        }\r\n\r\n        lastClick = System.currentTimeMillis();\r\n        lastRow = row;\r\n        return false;\r\n    }\r\n\r\n    public boolean focus() {\r\n        return table.hasFocus();\r\n    }\r\n\r\n    private void createConnectPanel() {\r\n        connectPanel = new JPanel();\r\n        connectPanel.setLayout(new BoxLayout(connectPanel, BoxLayout.X_AXIS));\r\n\r\n        JPanel pp1 = new JPanel();\r\n        pp1.setLayout(new GridLayout(0, 1));\r\n        connectPanel.add(pp1);\r\n\r\n        JPanel p = new JPanel();\r\n        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r\n        JLabel l = new JLabel(\"<html><p align=justify>Please specify connection preferences</p></html>\");\r\n        p.add(Box.createVerticalGlue());\r\n        JPanel p1 = new JPanel();\r\n        p1.setLayout(new FlowLayout());\r\n        p1.add(l);\r\n        p.add(p1);\r\n        pp1.add(p);\r\n\r\n        JButton connect = new JButton(\"Connect\");\r\n        connect.setIcon(getConnIcon());\r\n        connect.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent e) {\r\n                frame.connect.setVisible(true);\r\n                frame.connect.toFront();\r\n                if (frame.connect.bDialogOK) {\r\n                    frame.manager.initiated = false;\r\n                    int port = 54321;\r\n                    try {\r\n                        port = Integer.valueOf(frame.connect.sPort);\r\n                    } catch (Throwable t) {\r\n                    }\r\n                    frame.manager.connect(frame.connect.sHost, frame.connect.sUser, port);\r\n                } else {\r\n                    frame.manager.initiated = true;\r\n                }\r\n            }\r\n        });\r\n        p = new JPanel();\r\n        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));\r\n        p1 = new JPanel();\r\n        p1.setLayout(new FlowLayout());\r\n        p1.add(connect);\r\n        p.add(p1);\r\n        p.add(Box.createVerticalGlue());\r\n        pp1.add(p);\r\n    }\r\n\r\n    private JPopupMenu createPopup() {\r\n        popup = new JPopupMenu();\r\n\r\n        JMenuItem copy = new JMenuItem(\"Copy\");\r\n        copy.setIcon(getCopyIcon());\r\n        copy.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        copy();\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        copy.setToolTipText(\"Copy\");\r\n        popup.add(copy);\r\n\r\n        JMenuItem mkdir = new JMenuItem(\"Make dir\");\r\n        mkdir.setIcon(getMkDirIcon());\r\n        mkdir.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        makeDir();\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        mkdir.setToolTipText(\"Create directory\");\r\n        popup.add(mkdir);\r\n\r\n        JMenuItem remove = new JMenuItem(\"Remove\");\r\n        remove.setIcon(getRemoveIcon());\r\n        remove.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        removeFiles();\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        remove.setToolTipText(\"Delete\");\r\n        popup.add(remove);\r\n\r\n        popup.addSeparator();\r\n\r\n        JMenuItem quit = new JMenuItem(\"Quit\");\r\n        quit.setIcon(getExitIcon());\r\n        quit.addActionListener(new ActionListener() {\r\n            public void actionPerformed(ActionEvent arg0) {\r\n                Runnable r = new Runnable() {\r\n                    public void run() {\r\n                        System.exit(0);\r\n                    }\r\n                };\r\n                exec.execute(r);\r\n            }\r\n        });\r\n        quit.setToolTipText(\"Exit\");\r\n        popup.add(quit);\r\n\r\n        return popup;\r\n    }\r\n\r\n    protected void removeFiles() {\r\n        int[] rs = table.getSelectedRows();\r\n        if (rs == null || rs.length == 0) {\r\n            return;\r\n        }\r\n        ft.setEnabled(false);\r\n        Vector<FileHandler> v = new Vector<FileHandler>();\r\n        for (int i = 0; i < rs.length; i++) {\r\n            if (rs[i] < 0 || rs[i] >= rows.size()) continue;\r\n            // get the corresponding row in the table\r\n            final FileHandler fh = rows.get(rs[i]);\r\n            v.add(fh);\r\n        }\r\n        if (v.size() == 0) {\r\n            ft.setEnabled(true);\r\n            return;\r\n        }\r\n        for (int i = 0; i < v.size(); i++) {\r\n            final String fName = v.get(i).getName();\r\n            if (fName.equals(\"..\") || fName.equals(\".\")) {\r\n                v.remove(i);\r\n                i--;\r\n            }\r\n        }\r\n        if (v.size() == 0) {\r\n            ft.setEnabled(true);\r\n            return;\r\n        }\r\n        String[] files = new String[v.size()];\r\n        final String delim = session.getFileSeparator(); // here we are reffering to the local file system...\r\n        if (delim == null) return;\r\n        String cp = session.getWorkingDir();\r\n        if (cp == null) return;\r\n        if (!cp.endsWith(delim)) cp += delim;\r\n        StringBuffer buf = new StringBuffer();\r\n        System.out.println(\"About to delete:\");\r\n        buf.append(\"<html>Delete file\").append(files.length > 1 ? \"s\" : \"\").append(\"<br>\");\r\n        for (int i = 0; i < files.length; i++) {\r\n            files[i] = cp + v.get(i).getName();\r\n            if (i < 7) {\r\n                System.out.println(\"\\t\" + files[i]);\r\n                buf.append(\"&nbsp;&nbsp;<font color=#ff0000>\").append(v.get(i).getName()).append(\"</font>\");\r\n                if (i < files.length - 1 && i < 6) buf.append(\"<br>\");\r\n            }\r\n        }\r\n        if (files.length > 7) {\r\n            System.out.println(\"... \" + (files.length - 7) + \" more\");\r\n            buf.append(\"<br>...\").append(files.length - 7).append(\" more ?\");\r\n        } else {\r\n            buf.append(\" ?\");\r\n        }\r\n//\t\tint ret = JOptionPane.showConfirmDialog(ft, \"Delete \"+files.length+\" file\"+(files.length > 1 ? \"s\" : \"\") + \"?\", \"Confirm\", JOptionPane.YES_NO_OPTION);\r\n        int ret = JOptionPane.showConfirmDialog(ft, buf.toString(), \"Confirm\", JOptionPane.YES_NO_OPTION);\r\n        if (ret == JOptionPane.YES_OPTION) {\r\n//\t\t\tJOptionPane.showMessageDialog(ft, \"This functionality requires higher privileges\");\r\n            try {\r\n                session.removeFiles(files);\r\n            } catch (Exception e) {\r\n                JOptionPane.showMessageDialog(ft, e.toString());\r\n            }\r\n        }\r\n        setConnected(true);\r\n        ft.setEnabled(true);\r\n    }\r\n\r\n    /**\r\n     * Method used to create a new directory\r\n     */\r\n    protected void makeDir() {\r\n        ft.setEnabled(false);\r\n        String name = JOptionPane.showInputDialog(ft, \"Enter the name of the directory\");\r\n        if (name != null && name.length() > 0 && session != null) {\r\n            final String delim = session.getFileSeparator();\r\n            if (delim == null) return;\r\n            String cp = session.getWorkingDir();\r\n            if (cp == null) return;\r\n            if (!cp.endsWith(delim)) cp += delim;\r\n            try {\r\n                session.createDir(cp + name);\r\n                selectedDir = name;\r\n            } catch (Exception e) {\r\n                JOptionPane.showMessageDialog(ft, e.toString());\r\n            }\r\n            setConnected(true);\r\n        }\r\n        ft.setEnabled(true);\r\n        selectedDir = null;\r\n    }\r\n\r\n    protected void copy() {\r\n        synchronized (nf) {\r\n            if (transferMonitor == null)\r\n                transferMonitor = new TransferMonitor(ft, command != null, manager);\r\n        }\r\n        if (manager == null) return;\r\n        // is connected ?\r\n        if (!manager.isConnected()) {\r\n            JOptionPane.showMessageDialog(ft, \"Please connect first to the remote server\");\r\n            return;\r\n        }\r\n        if (!transferMonitor.finished())\r\n            return;\r\n        // get the list of selected files\r\n        int[] rs = table.getSelectedRows();\r\n        if (rs == null || rs.length == 0) {\r\n            setStatus(\"Unable to cp... no file is selected\");\r\n            return;\r\n        }\r\n        ft.setEnabled(false);\r\n        Vector<FileHandler> v = new Vector<FileHandler>();\r\n        for (int i = 0; i < rs.length; i++) {\r\n            if (rs[i] < 0 || rs[i] >= rows.size()) continue;\r\n            // get the corresponding row in the table\r\n            final FileHandler fh = rows.get(rs[i]);\r\n            v.add(fh);\r\n        }\r\n        if (v.size() == 0) {\r\n            ft.setEnabled(true);\r\n            setStatus(\"Unable to cp... no file is selected\");\r\n            return;\r\n        }\r\n        String[] files = new String[v.size()];\r\n        boolean isRecursive = false;\r\n        setStatus(\"Copying...\");\r\n        final String delim = session.getFileSeparator(); // here we are reffering to the local file system...\r\n        String cp = session.getWorkingDir();\r\n        if (!cp.endsWith(delim)) cp += delim;\r\n        for (int i = 0; i < files.length; i++) {\r\n            files[i] = cp + v.get(i).getName();\r\n            setStatus(files[i]);\r\n            isRecursive = isRecursive | v.get(i).isDir();\r\n        }\r\n        setStatus(\".\");\r\n        String ret = null;\r\n//\t\tif (transferMonitor == null)\r\n//\t\t\ttransferMonitor = new TransferMonitor(ft, command != null, manager);\r\n//\t\telse\r\n        transferMonitor.restart(ft, command != null);\r\n        if ((ret = manager.initiateTransfer(files, command != null, isRecursive)) != null) { // inform the manager to start transferring...\r\n            transferMonitor.start();\r\n            ft.setEnabled(true);\r\n            JOptionPane.showMessageDialog(ft, \"Cannot copy: \" + ret);\r\n            return;\r\n        }\r\n        transferMonitor.start();\r\n        ft.setEnabled(true);\r\n    }\r\n\r\n    protected void selectStartWith(String prefix) {\r\n        synchronized (getTreeLock()) {\r\n            ListSelectionModel model = table.getSelectionModel();\r\n            for (int i = 0; i < rows.size(); i++) {\r\n                FileHandler h = rows.get(i);\r\n                if (h.getName().startsWith(prefix)) {\r\n                    model.setSelectionInterval(i, i);\r\n                    if (!(table.getParent() instanceof JViewport)) {\r\n                        return;\r\n                    }\r\n                    JViewport view = (JViewport) table.getParent();\r\n                    Rectangle rect = table.getCellRect(i, 0, true);\r\n                    Point pt = view.getViewPosition();\r\n                    rect.setLocation(rect.x - pt.x, rect.y - pt.y);\r\n                    view.scrollRectToVisible(rect);\r\n                    return;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    public void hideSelection() {\r\n        showSelection = false;\r\n        table.repaint();\r\n    }\r\n\r\n    public void showSelection() {\r\n        showSelection = true;\r\n        ListSelectionModel model = table.getSelectionModel();\r\n        if (table.getSelectedRowCount() < 1) {\r\n            model.setSelectionInterval(0, 0);\r\n            if (!(table.getParent() instanceof JViewport)) {\r\n                return;\r\n            }\r\n            JViewport view = (JViewport) table.getParent();\r\n            Rectangle rect = table.getCellRect(0, 0, true);\r\n            Point pt = view.getViewPosition();\r\n            rect.setLocation(rect.x - pt.x, rect.y - pt.y);\r\n            view.scrollRectToVisible(rect);\r\n            table.revalidate();\r\n            table.repaint();\r\n        } else\r\n            table.repaint();\r\n    }\r\n\r\n    private final void setSelectedItem(JMenuItem item, boolean selected) {\r\n        if (!selected)\r\n            item.setBorder(BorderFactory.createRaisedBevelBorder());\r\n        else\r\n            item.setBorder(BorderFactory.createLoweredBevelBorder());\r\n    }\r\n\r\n    public void setEnabled(boolean enabled) {\r\n        headerRenderer.setEnabled(enabled);\r\n        headerRenderer.repaint();\r\n        cellRenderer.setEnabled(enabled);\r\n        cellRenderer.repaint();\r\n        table.revalidate();\r\n        table.repaint();\r\n//\t\troots.setEnabled(enabled);\r\n//\t\tparentDir.setEnabled(enabled);\r\n//\t\trootDir.setEnabled(enabled);\r\n//\t\thomeDir.setEnabled(enabled);\r\n//\t\trefreshDir.setEnabled(enabled);\r\n//\t\topenDir.setEnabled(enabled);\r\n        showIconItem.setEnabled(enabled);\r\n        showLengthItem.setEnabled(enabled);\r\n        showModifItem.setEnabled(enabled);\r\n        showAttribItem.setEnabled(enabled);\r\n        if (command != null) {\r\n            copy.setEnabled(enabled);\r\n            exit.setEnabled(enabled);\r\n        }\r\n    }\r\n\r\n    public void setShowIcon(boolean show) {\r\n        showIcon = show;\r\n        updateColumns();\r\n    }\r\n\r\n    public void setShowLength(boolean show) {\r\n        showLength = show;\r\n        updateColumns();\r\n    }\r\n\r\n    public void setShowModif(boolean show) {\r\n        showModif = show;\r\n        updateColumns();\r\n    }\r\n\r\n    public void setShowAttrib(boolean show) {\r\n        showAttrib = show;\r\n        updateColumns();\r\n    }\r\n\r\n    private void updateColumns() {\r\n        synchronized (this.getTreeLock()) {\r\n            columns.clear();\r\n            if (showIcon) {\r\n                columns.add(colNames[0]);\r\n            }\r\n            columns.add(colNames[1]);\r\n            if (showModif) {\r\n                columns.add(colNames[2]);\r\n            }\r\n            if (showLength) {\r\n                columns.add(colNames[3]);\r\n            }\r\n            if (showAttrib) {\r\n                columns.add(colNames[4]);\r\n            }\r\n        }\r\n        ((AbstractTableModel) table.getModel()).fireTableStructureChanged();\r\n        JTableHeader header = table.getTableHeader();\r\n        Enumeration<TableColumn> en = header.getColumnModel().getColumns();\r\n        if (en != null)\r\n            while (en.hasMoreElements()) {\r\n                TableColumn column = en.nextElement();\r\n                if (column != null) {\r\n                    String colName = column.getHeaderValue().toString();\r\n                    if (colName.equals(colNames[0]) || colName.length() == 0) {\r\n                        column.setPreferredWidth(25);\r\n                    }\r\n                    if (colName.equals(colNames[1])) {\r\n                        column.setPreferredWidth(1000);\r\n                    }\r\n                    if (colName.equals(colNames[2])) {\r\n                        column.setPreferredWidth(160);\r\n                    }\r\n                    if (colName.equals(colNames[3])) {\r\n                        column.setPreferredWidth(100);\r\n                    }\r\n                    if (colName.equals(colNames[4])) {\r\n                        column.setPreferredWidth(30);\r\n                    }\r\n                }\r\n            }\r\n    }\r\n\r\n    private void updateTable() {\r\n\r\n        synchronized (this.getTreeLock()) {\r\n            removeCurrentDir();\r\n            rows.clear();\r\n            // add the rows...\r\n            if (!session.isRoot()) {\r\n                FileHandler h = new FileHandler(\"..\", getUpDirIcon(), -1, -1, \"\", true);\r\n                rows.add(h);\r\n                parentDir.setEnabled(true);\r\n                rootDir.setEnabled(true);\r\n            } else {\r\n                parentDir.setEnabled(false);\r\n                rootDir.setEnabled(false);\r\n            }\r\n            // add the directories\r\n            for (Iterator<String> it = session.dirs.iterator(); it.hasNext(); ) {\r\n                String d = it.next();\r\n                FileHandler h = new FileHandler(d, session.icons.get(d), session.modif.get(d), -1, constructAttrib(d), true);\r\n                rows.add(h);\r\n            }\r\n            // add the rest of the files\r\n            for (Iterator<String> it = session.length.keySet().iterator(); it.hasNext(); ) {\r\n                String f = it.next();\r\n                try {\r\n                    FileHandler h = new FileHandler(f, session.icons.get(f), session.modif.get(f), session.length.get(f), constructAttrib(f), false);\r\n                    rows.add(h);\r\n                } catch (Throwable t) {\r\n//\t\t\t\t\tt.printStackTrace();\r\n                }\r\n            }\r\n            if (sortColumn != null)\r\n                sortTable();\r\n            else\r\n                ((AbstractTableModel) table.getModel()).fireTableDataChanged();\r\n        }\r\n        // update the amount of free space available\r\n        String freeSpace = session.freeSpace();\r\n        if (freeSpace != null && freeSpace.length() != 0) {\r\n            this.freeSpace.setText(\"<html>Free space: <font color=#ff0000>\" + freeSpace + \"</font></html\");\r\n            this.freeSpace.setBorder(BorderFactory.createEtchedBorder());\r\n        } else {\r\n            this.freeSpace.setText(\"\");\r\n            this.freeSpace.setBorder(null);\r\n        }\r\n        // also see the corresponding root of the current working directory and updated it in the combobox, neat :)\r\n        int max = -1;\r\n        int poz = -1;\r\n        boolean found = false;\r\n        String currentDir = session.getWorkingDir();\r\n        for (int i = 0; i < roots.getItemCount(); i++) {\r\n            String item = ((String) roots.getItemAt(i));\r\n            if (item == null) continue;\r\n            String r = session.getShortRootName(item);\r\n            if (r == null) continue;\r\n            r = r.toLowerCase(Locale.US);\r\n            if (r != null && currentDir != null && currentDir.toLowerCase(Locale.US).startsWith(r)) {\r\n                if (max < r.length()) {\r\n                    poz = i;\r\n                    max = r.length();\r\n                }\r\n                if (currentDir.equals(item))\r\n                    found = true;\r\n            }\r\n        }\r\n        if (!found) {\r\n            this.currentDir = currentDir;\r\n            ActionListener listener = null;\r\n            if (roots.getActionListeners() != null && roots.getActionListeners().length != 0) {\r\n                listener = roots.getActionListeners()[0];\r\n                roots.removeActionListener(listener);\r\n            }\r\n            Object o[] = new Object[roots.getItemCount()];\r\n            for (int i = 0; i < o.length; i++)\r\n                o[i] = roots.getItemAt(i);\r\n            roots.removeAllItems();\r\n            roots.addItem(currentDir);\r\n            for (int i = 0; i < o.length; i++)\r\n                roots.addItem(o[i]);\r\n            roots.setSelectedIndex(0);\r\n            roots.repaint();\r\n            roots.revalidate();\r\n            if (listener != null)\r\n                roots.addActionListener(listener);\r\n        } else if (max > 0 && roots.getSelectedIndex() != poz) {\r\n            ActionListener listener = null;\r\n            if (roots.getActionListeners() != null && roots.getActionListeners().length != 0) {\r\n                listener = roots.getActionListeners()[0];\r\n                roots.removeActionListener(listener);\r\n            }\r\n            roots.setSelectedIndex(poz);\r\n            roots.repaint();\r\n            roots.revalidate();\r\n            if (listener != null)\r\n                roots.addActionListener(listener);\r\n        }\r\n        if (max < 0 && found) rootDir.setEnabled(false);\r\n        if (command == null) {\r\n            setStatus(\"Current remote dir = \" + session.getWorkingDir());\r\n//\t\t\tString[] str = session.getRoots();\r\n//\t\t\tActionListener listener = roots.getActionListeners()[0];\r\n//\t\t\troots.removeActionListener(listener);\r\n//\t\t\troots.removeAllItems();\r\n//\t\t\tif (str != null)\r\n//\t\t\t\tfor (int i=0; i<str.length; i++)\r\n//\t\t\t\t\troots.addItem(str[i]);\r\n//\t\t\troots.addActionListener(listener);\r\n        } else\r\n            setStatus(\"Current local dir = \" + session.getWorkingDir());\r\n        table.revalidate();\r\n        table.repaint();\r\n        table.getTableHeader().repaint();\r\n        table.getTableHeader().revalidate();\r\n\r\n        if (lastDir != null) {\r\n            try {\r\n                Thread.sleep(200);\r\n            } catch (Exception e) {\r\n            }\r\n            synchronized (getTreeLock()) {\r\n                for (int i = 0; i < rows.size(); i++) {\r\n                    FileHandler h = rows.get(i);\r\n                    if (h.getName().equals(lastDir)) {\r\n                        table.setRowSelectionInterval(i, i);\r\n                        if (table.getParent() instanceof JViewport) {\r\n                            JViewport view = (JViewport) table.getParent();\r\n                            Rectangle rect = table.getCellRect(i, 0, true);\r\n                            Point pt = view.getViewPosition();\r\n                            rect.setLocation(rect.x - pt.x, rect.y - pt.y);\r\n                            view.scrollRectToVisible(rect);\r\n                            table.scrollRectToVisible(rect);\r\n                        }\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            lastDir = null;\r\n        } else if (selectedDir != null) {\r\n            synchronized (getTreeLock()) {\r\n                for (int i = 0; i < rows.size(); i++) {\r\n                    FileHandler h = rows.get(i);\r\n                    if (h.getName().equals(selectedDir)) {\r\n                        table.setRowSelectionInterval(i, i);\r\n                        if (table.getParent() instanceof JViewport) {\r\n                            JViewport view = (JViewport) table.getParent();\r\n                            Rectangle rect = table.getCellRect(i, 0, true);\r\n                            Point pt = view.getViewPosition();\r\n                            rect.setLocation(rect.x - pt.x, rect.y - pt.y);\r\n                            view.scrollRectToVisible(rect);\r\n                            table.scrollRectToVisible(rect);\r\n                        }\r\n                        break;\r\n                    }\r\n                }\r\n            }\r\n            selectedDir = null;\r\n        } else {\r\n            table.setRowSelectionInterval(0, 0);\r\n        }\r\n    }\r\n\r\n    private void sortTable() {\r\n        Collections.sort(rows, new ColumnSorter());\r\n        ((AbstractTableModel) table.getModel()).fireTableDataChanged();\r\n        table.getTableHeader().repaint();\r\n    }\r\n\r\n    private String constructAttrib(final String fileName) {\r\n        final StringBuffer buf = new StringBuffer();\r\n        if (session.read.containsKey(fileName) && session.read.get(fileName))\r\n            buf.append(\"r\");\r\n        else buf.append(\"-\");\r\n        if (session.write.containsKey(fileName) && session.write.get(fileName))\r\n            buf.append(\"w\");\r\n        else buf.append(\"-\");\r\n        return buf.toString();\r\n    }\r\n\r\n    private Icon getUpDirIcon() {\r\n        if (upDirIcon != null) return upDirIcon;\r\n        try {\r\n            URL r = getClass().getResource(pack + \"/icons/up_dir.png\");\r\n            upDirIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return upDirIcon;\r\n    }\r\n\r\n    private Icon getRootIcon() {\r\n        if (rootIcon != null) return rootIcon;\r\n        try {\r\n            URL r = getClass().getResource(pack + \"/icons/rootIcon.png\");\r\n            rootIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return rootIcon;\r\n    }\r\n\r\n    private Icon getCopyIcon() {\r\n        if (copyIcon != null) return copyIcon;\r\n        try {\r\n            URL r = getClass().getResource(pack + \"/icons/copy.png\");\r\n            copyIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return copyIcon;\r\n    }\r\n\r\n    private Icon getExitIcon() {\r\n        if (exitIcon != null) return exitIcon;\r\n        try {\r\n            URL r = getClass().getResource(pack + \"/icons/exit.jpg\");\r\n            exitIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return exitIcon;\r\n    }\r\n\r\n    private Icon getOpenDirIcon() {\r\n        if (openDirIcon != null) return openDirIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/openfolder.png\");\r\n            openDirIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return openDirIcon;\r\n    }\r\n\r\n    private Icon getRefreshIcon() {\r\n        if (refreshIcon != null) return refreshIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/refresh.gif\");\r\n            refreshIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return refreshIcon;\r\n    }\r\n\r\n    private Icon getHomeIcon() {\r\n        if (openHomeIcon != null) return openHomeIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/home_icon.png\");\r\n            openHomeIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return openHomeIcon;\r\n    }\r\n\r\n    private Icon getSelectIcon() {\r\n        if (selectIcon != null) return selectIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/select.gif\");\r\n            selectIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return selectIcon;\r\n    }\r\n\r\n    private Icon getSortAIcon() {\r\n        if (sortAIcon != null) return sortAIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/sort_up.gif\");\r\n            sortAIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return sortAIcon;\r\n    }\r\n\r\n    private Icon getSortDIcon() {\r\n        if (sortDIcon != null) return sortDIcon;\r\n        try {\r\n            URL url = getClass().getResource(pack + \"/icons/sort_down.gif\");\r\n            sortDIcon = new ImageIcon(url);\r\n        } catch (Exception e) {\r\n        }\r\n        return sortDIcon;\r\n    }\r\n\r\n    public void setConnected(boolean connected) {\r\n        if (!connected) {\r\n            removeAll();\r\n            add(connectPanel, BorderLayout.CENTER);\r\n            setEnabled(false);\r\n            revalidate();\r\n            repaint();\r\n        } else {\r\n            removeAll();\r\n            add(tablePanel, BorderLayout.CENTER);\r\n            setEnabled(true);\r\n            revalidate();\r\n            repaint();\r\n            ft.setEnabled(false);\r\n            String[] str = null;\r\n            try {\r\n                str = session.getRoots();\r\n            } catch (Exception e) {\r\n                str = new String[0];\r\n                JOptionPane.showMessageDialog(ft, e.toString());\r\n            }\r\n            ActionListener listener = null;\r\n            if (roots.getActionListeners() != null && roots.getActionListeners().length != 0) {\r\n                listener = roots.getActionListeners()[0];\r\n                roots.removeActionListener(listener);\r\n            }\r\n            roots.removeAllItems();\r\n            if (str != null)\r\n                for (int i = 0; i < str.length; i++)\r\n                    roots.addItem(str[i]);\r\n            if (listener != null)\r\n                roots.addActionListener(listener);\r\n            try {\r\n                session.setAbsoluteDir(session.getWorkingDir());\r\n            } catch (Exception e) {\r\n                JOptionPane.showMessageDialog(ft, e.toString());\r\n            }\r\n            updateTable();\r\n            ft.setEnabled(true);\r\n            table.requestFocusInWindow();\r\n        }\r\n    }\r\n\r\n    public void setStatus(String status) {\r\n        if (statusBar == null) return;\r\n        status = status.replace(\"<\", \"[\").replace(\">\", \"]\");\r\n        statusBar.addText(status + \"\\n\");\r\n    }\r\n\r\n    public final JTable getTable() {\r\n        return table;\r\n    }\r\n\r\n    private Icon getMkDirIcon() {\r\n        if (mkdirIcon != null) return mkdirIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/mkdir.png\");\r\n            mkdirIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return mkdirIcon;\r\n    }\r\n\r\n    private Icon getRemoveIcon() {\r\n        if (removeIcon != null) return removeIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/delete.png\");\r\n            removeIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return removeIcon;\r\n    }\r\n\r\n    private Icon getConnIcon() {\r\n        if (connIcon != null) return connIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/connect2.gif\");\r\n            connIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return connIcon;\r\n    }\r\n\r\n    private Icon getVertIcon() {\r\n        if (verticalIcon != null) return verticalIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"icons/vertical.jpg\");\r\n            verticalIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return verticalIcon;\r\n    }\r\n\r\n    private final class FileHandler {\r\n        private final String name;\r\n        private final Icon icon;\r\n        private final long modif;\r\n        private final long size;\r\n        private final String attrib;\r\n        private final boolean isDir;\r\n\r\n        public FileHandler(String name, Icon icon, long modif, long size, String attrib, boolean isDir) {\r\n            this.name = name;\r\n            this.icon = icon;\r\n            this.modif = modif;\r\n            this.size = size;\r\n            this.attrib = attrib;\r\n            this.isDir = isDir;\r\n        }\r\n\r\n        public final String getName() {\r\n            if (name == null) return \" \";\r\n            return name;\r\n        }\r\n\r\n        public final Icon getIcon() {\r\n            return icon;\r\n        }\r\n\r\n        public final String getModif() {\r\n            if (modif <= 0) return \" \";\r\n            return \" \" + dateFormat.format(new Date(modif));\r\n        }\r\n\r\n        public final long getModifL() {\r\n            return modif;\r\n        }\r\n\r\n        public final String getSize() {\r\n            if (size <= 0) return \" \";\r\n            double s = size;\r\n            if (s > 1024) s /= 1024;\r\n            else return \" \" + nf.format(s) + \" B\";\r\n            if (s > 1024) s /= 1024;\r\n            else return \" \" + nf.format(s) + \" KB\";\r\n            if (s > 1024) s /= 1024;\r\n            else return \" \" + nf.format(s) + \" MB\";\r\n            if (s > 1024) s /= 1024;\r\n            else return \" \" + nf.format(s) + \" GB\";\r\n            return \" \" + nf.format(s) + \" PB\";\r\n        }\r\n\r\n        public final long getSizeL() {\r\n            return size;\r\n        }\r\n\r\n        public final String getAttrib() {\r\n            if (attrib == null) return \" \";\r\n            return \" \" + attrib;\r\n        }\r\n\r\n        public final boolean isDir() {\r\n            return isDir;\r\n        }\r\n    }\r\n\r\n    private class MyTableModel extends AbstractTableModel {\r\n\r\n        public int getRowCount() {\r\n            return rows.size();\r\n        }\r\n\r\n        public int getColumnCount() {\r\n            return columns.size();\r\n        }\r\n\r\n        public String getColumnName(int column) {\r\n            if (column < 0 || column >= columns.size()) return \"\";\r\n            final String colName = columns.get(column);\r\n            if (colName.equals(colNames[0])) return \"\";\r\n            return colName;\r\n        }\r\n\r\n        public boolean isCellEditable(int arg0, int arg1) {\r\n            return false;\r\n        }\r\n\r\n        /*\r\n         * JTable uses this method to determine the default renderer/\r\n         * editor for each cell.  If we didn't implement this method,\r\n         * then the last column would contain text (\"true\"/\"false\"),\r\n         * rather than a check box.\r\n         */\r\n        public Class getColumnClass(int c) {\r\n            final String col = columns.get(c);\r\n            if (col.equals(colNames[0]))\r\n                return Icon.class;\r\n            return String.class;\r\n//            return getValueAt(0, c).getClass();\r\n        }\r\n\r\n        public Object getValueAt(int row, int col) {\r\n            FileHandler h = null;\r\n            synchronized (rows) {\r\n                if (row < 0 || row >= rows.size()) return null;\r\n                h = rows.get(row);\r\n            }\r\n            String colName = null;\r\n            synchronized (columns) {\r\n                if (col < 0 || col >= columns.size()) return null;\r\n                colName = columns.get(col);\r\n            }\r\n            table.getColumnModel().getColumn(col).setResizable(true);\r\n\r\n            if (colName.equals(colNames[0])) {\r\n                table.getColumnModel().getColumn(col).setHeaderRenderer(headerRenderer);\r\n                table.getColumnModel().getColumn(col).setCellRenderer(cellRenderer);\r\n                return h.getIcon();\r\n            }\r\n            if (colName.equals(colNames[1])) {\r\n                table.getColumnModel().getColumn(col).setHeaderRenderer(headerRenderer);\r\n                table.getColumnModel().getColumn(col).setCellRenderer(cellRenderer);\r\n                return h.getName();\r\n            }\r\n            if (colName.equals(colNames[2])) {\r\n                table.getColumnModel().getColumn(col).setHeaderRenderer(headerRenderer);\r\n                table.getColumnModel().getColumn(col).setCellRenderer(cellRenderer);\r\n                return h.getModif();\r\n            }\r\n            if (colName.equals(colNames[3])) {\r\n                table.getColumnModel().getColumn(col).setHeaderRenderer(headerRenderer);\r\n                table.getColumnModel().getColumn(col).setCellRenderer(cellRenderer);\r\n                return h.getSize();\r\n            }\r\n            if (colName.equals(colNames[4])) {\r\n                table.getColumnModel().getColumn(col).setHeaderRenderer(headerRenderer);\r\n                table.getColumnModel().getColumn(col).setCellRenderer(cellRenderer);\r\n                return h.getAttrib();\r\n            }\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public class MyTableHeaderRenderer extends JLabel implements TableCellRenderer {\r\n\r\n        private Border border = BorderFactory.createRaisedBevelBorder();\r\n\r\n        // This method is called each time a column header\r\n        // using this renderer needs to be rendered.\r\n        public Component getTableCellRendererComponent(JTable table, Object value,\r\n                                                       boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {\r\n            // 'value' is column header value of column 'vColIndex'\r\n            // rowIndex is always -1\r\n            // isSelected is always false\r\n            // hasFocus is always false\r\n            // Configure the component with the specified value\r\n            setText(value.toString());\r\n            setForeground(Color.red);\r\n            // Set tool tip if desired\r\n            setToolTipText((String) value);\r\n            setBorder(border);\r\n            if (sortColumn != null && sortColumn.equals(value.toString())) {\r\n                if (sortAsc) setIcon(getSortAIcon());\r\n                else setIcon(getSortDIcon());\r\n            } else if (sortColumn != null && sortColumn.equals(colNames[0]) && vColIndex == 0) {\r\n                if (sortAsc) setIcon(getSortAIcon());\r\n                else setIcon(getSortDIcon());\r\n            } else setIcon(null);\r\n            // Since the renderer is a component, return itself\r\n            return this;\r\n        }\r\n\r\n        // The following methods override the defaults for performance reasons\r\n        public void validate() {\r\n        }\r\n\r\n        public void revalidate() {\r\n        }\r\n\r\n        protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {\r\n        }\r\n\r\n        public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {\r\n        }\r\n    }\r\n\r\n    private class ColumnHeaderListener extends MouseAdapter {\r\n        public void mouseClicked(MouseEvent evt) {\r\n            JTable table = ((JTableHeader) evt.getSource()).getTable();\r\n            TableColumnModel colModel = table.getColumnModel();\r\n            // The index of the column whose header was clicked\r\n            int vColIndex = colModel.getColumnIndexAtX(evt.getX());\r\n            // Return if not clicked on any column header\r\n            if (vColIndex == -1) {\r\n                return;\r\n            }\r\n            // get the name of the column\r\n            String col = columns.get(vColIndex);\r\n            if (sortColumn == null) {\r\n                sortColumn = col;\r\n                sortAsc = true;\r\n            } else {\r\n                if (sortColumn.equals(col)) {\r\n                    sortAsc = !sortAsc;\r\n                } else {\r\n                    sortColumn = col;\r\n                    sortAsc = true;\r\n                }\r\n            }\r\n            sortTable();\r\n        }\r\n    }\r\n\r\n    // This comparator is used to sort vectors of data\r\n    public class ColumnSorter implements Comparator {\r\n        ColumnSorter() {\r\n        }\r\n\r\n        public int compare(Object a, Object b) {\r\n            FileHandler fh1 = (FileHandler) a;\r\n            FileHandler fh2 = (FileHandler) b;\r\n            if (fh1.getName().equals(\"..\")) return -1;\r\n            if (fh2.getName().equals(\"..\")) return 1;\r\n            if (fh1.isDir() && !fh2.isDir())\r\n                return -1;\r\n            if (!fh1.isDir() && fh2.isDir())\r\n                return 1;\r\n            if (sortColumn.equals(colNames[0])) {\r\n                if (fh1.getIcon() == null && fh2.getIcon() == null)\r\n                    return 0;\r\n                if (fh1.getIcon() == null)\r\n                    return 1;\r\n                if (fh2.getIcon() == null)\r\n                    return -1;\r\n                if (sortAsc)\r\n                    return fh1.getIcon().toString().compareTo(fh2.getIcon().toString());\r\n                return fh2.getIcon().toString().compareTo(fh1.getIcon().toString());\r\n            }\r\n            if (sortColumn.equals(colNames[2])) {\r\n                if (fh1.getModifL() < fh2.getModifL()) return (sortAsc ? 1 : -1);\r\n                else if (fh1.getModifL() == fh2.getModifL()) return 0;\r\n                return (sortAsc ? -1 : 1);\r\n            }\r\n            if (sortColumn.equals(colNames[3])) {\r\n                if (fh1.getSizeL() < fh2.getSizeL()) return (sortAsc ? 1 : -1);\r\n                else if (fh1.getSizeL() == fh2.getSizeL()) return 0;\r\n                return (sortAsc ? -1 : 1);\r\n            }\r\n            if (sortColumn.equals(colNames[4])) {\r\n                if (sortAsc)\r\n                    return fh1.getAttrib().compareTo(fh2.getAttrib());\r\n                return fh2.getAttrib().compareTo(fh1.getAttrib());\r\n            }\r\n            if (sortAsc)\r\n                return fh1.getName().compareTo(fh2.getName());\r\n            return fh2.getName().compareTo(fh1.getName());\r\n        }\r\n//\t\tpublic int compare(Object a, Object b) {\r\n//\t\t\tFileHandler fh1 = (FileHandler)a;\r\n//\t\t\tFileHandler fh2 = (FileHandler)b;\r\n//\t\t\tif (fh1.getName().equals(\"..\")) return -1;\r\n//\t\t\tif (fh2.getName().equals(\"..\")) return 1;\r\n//\t\t\tif (sortColumn.equals(colNames[0])) {\r\n//\t\t\t\tif (fh1.getIcon() == null && fh2.getIcon() == null)\r\n//\t\t\t\t\treturn 0;\r\n//\t\t\t\tif (fh1.getIcon() == null)\r\n//\t\t\t\t\treturn 1;\r\n//\t\t\t\tif (fh2.getIcon() == null)\r\n//\t\t\t\t\treturn -1;\r\n//\t\t\t\tif (fh1.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return -1;\r\n//\t\t\t\tif (fh2.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return 1;\r\n//\t\t\t\tif (sortAsc)\r\n//\t\t\t\t\treturn fh1.getIcon().toString().compareTo(fh2.getIcon().toString());\r\n//\t\t\t\treturn fh2.getIcon().toString().compareTo(fh1.getIcon().toString());\r\n//\t\t\t}\r\n//\t\t\tif (sortColumn.equals(colNames[2])) {\r\n//\t\t\t\tif (fh1.getIcon() != null && fh2.getIcon() != null) {\r\n//\t\t\t\t\tif (fh1.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return -1;\r\n//\t\t\t\t\tif (fh2.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return 1;\r\n//\t\t\t\t}\r\n//\t\t\t\tif (fh1.getModifL() < fh2.getModifL()) return (sortAsc ? 1 : -1);\r\n//\t\t\t\telse if (fh1.getModifL() == fh2.getModifL()) return 0;\r\n//\t\t\t\treturn (sortAsc ? -1 : 1);\r\n//\t\t\t}\r\n//\t\t\tif (sortColumn.equals(colNames[3])) {\r\n//\t\t\t\tif (fh1.getIcon() != null && fh2.getIcon() != null) {\r\n//\t\t\t\t\tif (fh1.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return -1;\r\n//\t\t\t\t\tif (fh2.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return 1;\r\n//\t\t\t\t}\r\n//\t\t\t\tif (fh1.getSizeL() < fh2.getSizeL()) return (sortAsc ? 1 : -1);\r\n//\t\t\t\telse if (fh1.getSizeL() == fh2.getSizeL()) return 0;\r\n//\t\t\t\treturn (sortAsc ? -1 : 1);\r\n//\t\t\t}\r\n//\t\t\tif (sortColumn.equals(colNames[4])) {\r\n//\t\t\t\tif (fh1.getIcon() != null && fh2.getIcon() != null) {\r\n//\t\t\t\t\tif (fh1.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return -1;\r\n//\t\t\t\t\tif (fh2.getIcon().toString().toLowerCase(Locale.US).contains(\"folder\")) return 1;\r\n//\t\t\t\t}\r\n//\t\t\t\tif (sortAsc)\r\n//\t\t\t\t\treturn fh1.getAttrib().compareTo(fh2.getAttrib());\r\n//\t\t\t\treturn fh2.getAttrib().compareTo(fh1.getAttrib());\r\n//\t\t\t}\r\n//\t\t\tif (sortAsc)\r\n//\t\t\t\treturn fh1.getName().compareTo(fh2.getName());\r\n//\t\t\treturn fh2.getName().compareTo(fh1.getName());\r\n//\t\t}\r\n    }\r\n\r\n    public class MyTableCellRenderer extends DefaultTableCellRenderer {\r\n        public Component getTableCellRendererComponent(JTable table, Object value,\r\n                                                       boolean isSelected, boolean hasFocus, int rowIndex, int vColIndex) {\r\n            Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, rowIndex, vColIndex);\r\n            final String col = columns.get(vColIndex);\r\n            if (isSelected && showSelection) {\r\n                if (col.equals(colNames[0]) || col.equals(colNames[2]) || col.equals(colNames[4])) {\r\n                    c.setBackground(c3);\r\n                } else\r\n                    c.setBackground(c1);\r\n            } else {\r\n                if (col.equals(colNames[0]) || col.equals(colNames[2]) || col.equals(colNames[4]))\r\n                    c.setBackground(focus() ? c44 : cg);\r\n                else\r\n                    c.setBackground(focus() ? c2 : cg);\r\n            }\r\n            if (value instanceof Icon) {\r\n                ((JLabel) c).setIcon((Icon) value);\r\n                ((JLabel) c).setText(null);\r\n            } else {\r\n                ((JLabel) c).setText((String) value);\r\n                ((JLabel) c).setIcon(null);\r\n//                int availableWidth = table.getColumnModel().getColumn(vColIndex).getWidth();\r\n//    \t\t\tavailableWidth -= table.getIntercellSpacing().getWidth();\r\n//    \t\t\tString cellText = getText();\r\n//    \t\t\tFontMetrics fm = getFontMetrics( getFont() );\r\n//\r\n//    \t\t\tif (fm.stringWidth(cellText) > availableWidth) {\r\n//    \t\t\t\tString dots = \"...\";\r\n//    \t\t\t\tint textWidth = fm.stringWidth( dots );\r\n//    \t\t\t\tint nChars = cellText.length() - 1;\r\n//    \t\t\t\tfor (; nChars > 0; nChars--) {\r\n//    \t\t\t\t\ttextWidth += fm.charWidth(cellText.charAt(nChars));\r\n//     \t\t\t\t\tif (textWidth > availableWidth) {\r\n//    \t\t\t\t\t\tbreak;\r\n//    \t\t\t\t\t}\r\n//    \t\t\t\t}\r\n//     \t\t\t\tsetText( dots + cellText.substring(nChars + 1) );\r\n//    \t\t\t}\r\n            }\r\n            ((JLabel) c).setBorder(null);\r\n\r\n            return c;\r\n        }\r\n    }\r\n\r\n}\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/GUISSHControlStream.java",
    "content": "/*\n * $Id: SSHControlStream.java 346 2007-08-16 13:48:25Z ramiro $\n */\npackage lia.util.net.copy.gui;\n\nimport lia.util.net.common.SSHControlStream;\n\nimport javax.swing.*;\nimport java.io.IOException;\n\n/**\n * @author Ciprian Dobre\n */\npublic class GUISSHControlStream extends SSHControlStream {\n\n    private JDialog connDialog;\n\n    /**\n     * Creates a new SSH control connection on the default ssh port.\n     * <p>\n     * Same as {@link #GUISSHControlStream(String, String, int, JDialog)} GUISSHControlStream(hostname, username, 22)}\n     *\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public GUISSHControlStream(String hostname, String username, JDialog connDialog) {\n        this(hostname, username, 22, connDialog);\n    }\n\n    /**\n     * Creates a new SSH control connection on the specified remote sshd port\n     *\n     * @param port:     remote sshd port\n     * @param hostname: remote host\n     * @param username: remote account\n     * @throws IOException in case of failure\n     */\n    public GUISSHControlStream(String hostname, String username, int port, JDialog connDialog) {\n        super(hostname, username, port);\n        this.connDialog = connDialog;\n    }\n\n    public String getPassword(String message) throws IOException {\n        connDialog.setVisible(false);\n        System.out.println(message);\n        JPasswordField pwd = new JPasswordField(10);\n        int action = JOptionPane.showConfirmDialog(null, pwd, \"Enter Password\", JOptionPane.OK_CANCEL_OPTION);\n        if (action != JOptionPane.OK_OPTION) {\n            throw new IOException(\"Cancel, X or escape key selected\");\n        }\n        connDialog.setVisible(true);\n        return new String(pwd.getPassword());\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/HelpDialog.java",
    "content": "/*\n * $Id: HelpDialog.java 387 2007-08-21 13:17:02Z cipsm $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.*;\nimport java.net.URL;\n\npublic class HelpDialog extends JDialog {\n\n    private ImageIcon caltechIcon;\n\n    public HelpDialog(JFrame parent) {\n        super(parent, \"Key mappings\", true);\n        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));\n\n        getContentPane().add(constructPanel(\"F5\", \"Copy selected files\"));\n        getContentPane().add(constructPanel(\"F7\", \"Create new dir\"));\n        getContentPane().add(constructPanel(\"F8/Del\", \"Remove selected files\"));\n        getContentPane().add(constructPanel(\"F10\", \"Quit the application\"));\n        getContentPane().add(constructPanel(\"Tab\", \"Change focus\"));\n        getContentPane().add(constructPanel(\"Enter\", \"Change selected directory\"));\n        getContentPane().add(constructPanel(\"Arrows up/down\", \"Moves the cursor\"));\n        getContentPane().add(constructPanel(\"Ctrl/Shift + Arrows up/down\", \"Select a range of files\"));\n\n        setVisible(false);\n        setSize(200, 100);\n        setBackground(new Color(15724527));\n        setResizable(false);\n\n        JButton okButton = new JButton(\"OK\");\n        okButton.setMinimumSize(new Dimension(190, 22));\n        okButton.setPreferredSize(new Dimension(190, 22));\n        JPanel p1 = new JPanel();\n        p1.setLayout(new BorderLayout());\n        p1.add(okButton, BorderLayout.CENTER);\n        getContentPane().add(p1);\n        okButton.addActionListener(new ActionListener() {\n            public void actionPerformed(ActionEvent e) {\n                setVisible(false);\n            }\n        });\n        pack();\n    }\n\n    private final JPanel constructPanel(String key, String label) {\n        final JPanel p = new JPanel();\n        p.setOpaque(false);\n        p.setLayout(new BorderLayout());\n        JLabel l = new JLabel(\"<html><p align=center><font color=#ff0000><b>\" + key + \"</b></font> - \" + label + \"</p></html>\");\n        p.add(l, BorderLayout.CENTER);\n        return p;\n    }\n\n    /**\n     * Shows or hides the component depending on the Boolean flag b.\n     *\n     * @param b if true, show the component; otherwise, hide the\n     *          component.\n     * @See java.awt.Component#isVisible\n     */\n    public void setVisible(boolean b) {\n        if (b) {\n            Dimension bounds = Toolkit.getDefaultToolkit().getScreenSize();\n            Dimension abounds = getSize();\n            setLocation((bounds.width - abounds.width) / 2, (bounds.height - abounds.height) / 3);\n        }\n        super.setVisible(b);\n    }\n\n    public Icon getCaltechIcon() {\n        if (caltechIcon != null) return caltechIcon;\n        try {\n            URL url = getClass().getResource(\"icons/caltech.gif\");\n            caltechIcon = new ImageIcon(url);\n        } catch (Throwable t) {\n        }\n        return caltechIcon;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/PreferencesHandler.java",
    "content": "/*\n * $Id: PreferencesHandler.java 390 2007-08-22 09:46:15Z cipsm $\n */\npackage lia.util.net.copy.gui;\n\nimport java.io.*;\nimport java.util.Properties;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Ciprian Dobre\n */\npublic class PreferencesHandler {\n\n    /**\n     * Logger used by this class\n     */\n    static final transient Logger logger = Logger.getLogger(PreferencesHandler.class.getCanonicalName());\n    final static Properties p = new Properties();\n    static String sPrefsFile;\n\n    static {\n        sPrefsFile = System.getProperty(\"user.home\", \".\") + System.getProperty(\"file.separator\") + \".fdt\" +\n                System.getProperty(\"file.separator\") + \"gui.props\";\n        try { // first try and check if the dirs exists...\n            final File file = new File(System.getProperty(\"user.home\", \".\") + System.getProperty(\"file.separator\") + \".fdt\");\n            file.mkdirs();\n        } catch (Throwable t) {\n        }\n        try {\n            //check we can write here\n            final File file = new File(sPrefsFile);\n            if (file.createNewFile())\n                file.delete();\n        } catch (IOException e) {\n            // resolve problems with buggy system reporting user.home as the parent dir for user dirs\n            sPrefsFile = System.getProperty(\"user.home\", \".\") + System.getProperty(\"file.separator\") + System.getProperty(\"user.name\") + System.getProperty(\"file.separator\")\n                    + \".fdt\" + System.getProperty(\"file.separator\") + \"gui.props\";\n        }\n        System.out.println(\"Using [\" + sPrefsFile + \"] as preferences file\");\n        load();\n    }\n\n    public static synchronized void load() {\n        // Create an input stream on a file\n        InputStream is = null;\n        try {\n            File f = new File(sPrefsFile);\n            if (!f.exists())\n                return;\n            is = new FileInputStream(f);\n        } catch (FileNotFoundException e) {\n            logger.log(Level.WARNING, \"Got exception \" + e.getLocalizedMessage(), e);\n        }\n        // Import preference data\n        try {\n            p.load(is);\n        } catch (IOException e) {\n            logger.log(Level.WARNING, \"Got exception \" + e.getLocalizedMessage(), e);\n        }\n    }\n\n    public static synchronized void save() {\n        try {\n            File f = new File(sPrefsFile);\n            try {\n                f.createNewFile();\n            } catch (Throwable t) {\n            }\n            FileOutputStream fos = new FileOutputStream(f);\n            // Export the node to a file\n            p.store(fos, null);\n            fos.close();\n        } catch (IOException e) {\n            logger.log(Level.WARNING, \"Got exception \" + e.getLocalizedMessage(), e);\n        }\n    }\n\n    public static synchronized String get(String key, String def) {\n        return p.getProperty(key, def);\n    }\n\n    public static synchronized void put(String key, String value) {\n        p.setProperty(key, value);\n    }\n\n    public static synchronized boolean getBoolean(String key, boolean def) {\n        try {\n            return Boolean.valueOf(p.getProperty(key, \"\" + def));\n        } catch (Exception e) {\n            return def;\n        }\n    }\n\n    public static synchronized void putBoolean(String key, boolean value) {\n        p.setProperty(key, \"\" + value);\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/ProgressBarUI.java",
    "content": "package lia.util.net.copy.gui;\r\n\r\nimport javax.swing.*;\r\nimport javax.swing.plaf.*;\r\nimport java.awt.*;\r\nimport java.awt.event.*;\r\nimport java.awt.image.*;\r\n\r\npublic class ProgressBarUI extends javax.swing.plaf.ProgressBarUI implements ImageObserver,\r\n        ActionListener {\r\n\r\n    private static final GradientPaint foregroundColour = new GradientPaint(0, 0, new Color(85, 82, 137), 300, 0, new Color(137, 255, 0));\r\n    private static final Color backgroundColour = new Color(238, 241, 238);\r\n\r\n    private static final int STRIPE_SIZE = 11;\r\n    public int startOffset = 0;\r\n    JComponent c;\r\n    private BufferedImage image = null;\r\n    private javax.swing.Timer timer = null;\r\n    private javax.swing.plaf.ProgressBarUI defaultUI;\r\n\r\n    public static ComponentUI createUI(JComponent c) {\r\n        return new ProgressBarUI();\r\n    }\r\n\r\n    public void paint(Graphics g, JComponent c) {\r\n//\t\tGet size\r\n        Insets insets = c.getInsets();\r\n\r\n        this.c = c;\r\n\r\n        int x = insets.left;\r\n        int y = insets.top;\r\n        int width = c.getWidth() - insets.left - insets.right;\r\n        int height = c.getHeight() - insets.top - insets.bottom;\r\n\r\n        JProgressBar bar = (JProgressBar) c;\r\n        int minimum = bar.getMinimum();\r\n        int maximum = bar.getMaximum();\r\n        int value = bar.getValue();\r\n\r\n        if (bar.isIndeterminate()) {\r\n            paintIndeterminateTimeProgress(g, x, y, width, height);\r\n            if (timer == null)\r\n                timer = new javax.swing.Timer(20, this);\r\n            timer.start();\r\n        } else {\r\n            if (timer != null)\r\n                timer.stop();\r\n\r\n            paintProgress(g, x, y, width, height, minimum, maximum, value);\r\n        }\r\n        if (((JProgressBar) c).isBorderPainted()) {\r\n            g.setColor(Color.black);\r\n            g.drawRect(x, y, width - 1, height - 1);\r\n        }\r\n    }\r\n\r\n    private void paintProgress(Graphics g, int x, int y, int width,\r\n                               int height, int minimum, int maximum,\r\n                               int value) {\r\n        float percent =\r\n                (float) (value - minimum) /\r\n                        (float) (maximum - minimum);\r\n\r\n        int highlightWidth = (int) (width * percent);\r\n        ((Graphics2D) g).setPaint(foregroundColour);\r\n        g.fillRect(0, 0, width, height);\r\n\r\n        if (highlightWidth < width) {\r\n            g.setColor(backgroundColour);\r\n            g.fillRect(highlightWidth + 1, y, width - highlightWidth,\r\n                    height);\r\n        }\r\n    }\r\n\r\n    private void paintIndeterminateTimeProgress(Graphics g, int x, int y,\r\n                                                int width, int height) {\r\n\r\n//\t\tCreate buffer of stripe pattern if we havent already\r\n        if (image == null) {\r\n//\t\t\tCreate buffer image longer than main image so we can\r\n//\t\t\tcreate scrolling effect merely by drawing it at \r\n//\t\t\tan offset\r\n            int bufferWidth = width + 4 * STRIPE_SIZE;\r\n\r\n            image = new BufferedImage(bufferWidth, height,\r\n                    BufferedImage.TYPE_3BYTE_BGR);\r\n            Graphics bufferGraphics = image.getGraphics();\r\n\r\n//\t\t\tFill background\r\n            bufferGraphics.setColor(backgroundColour);\r\n            bufferGraphics.fillRect(0, 0, bufferWidth, height);\r\n\r\n            int xoffset = 0;\r\n\r\n//\t\t\tDraw pattern\r\n            ((Graphics2D) bufferGraphics).setPaint(foregroundColour);\r\n\r\n            for (int yoffset = 0; yoffset <= height; yoffset++) {\r\n\r\n                drawStrippedLine(bufferGraphics, STRIPE_SIZE,\r\n                        xoffset, yoffset, bufferWidth);\r\n                xoffset++;\r\n\r\n                if (xoffset >= STRIPE_SIZE * 2)\r\n                    xoffset = 0;\r\n            }\r\n        }\r\n\r\n//\t\tDraw image to screen\r\n        g.drawImage(image, -startOffset, y, this);\r\n\r\n//\t\tDraw at different offset next time to get \"movement\"\r\n//\t\tpattern\r\n        startOffset += 1;\r\n\r\n        if (startOffset >= STRIPE_SIZE * 2)\r\n            startOffset -= STRIPE_SIZE * 2;\r\n    }\r\n\r\n    private void drawStrippedLine(Graphics g, int stripeSize, int x, int y,\r\n                                  int width) {\r\n\r\n        int xoffset = x;\r\n\r\n        while (xoffset < width) {\r\n            g.drawLine(xoffset,\r\n                    y,\r\n                    xoffset + stripeSize,\r\n                    y);\r\n            xoffset += stripeSize * 2;\r\n        }\r\n    }\r\n\r\n    public boolean imageUpdate(Image image, int infofloags, int x, int y,\r\n                               int width, int height) {\r\n        return true;\r\n    }\r\n\r\n    public void actionPerformed(java.awt.event.ActionEvent actionEvent) {\r\n        if (c != null)\r\n            c.repaint();\r\n    }\r\n\r\n    public Dimension getMinimumSize(JComponent component) {\r\n        return new Dimension(50, 15);\r\n    }\r\n\r\n    public Dimension getPreferredSize(JComponent component) {\r\n        return new Dimension(50, 15);\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/RemoteSessionManager.java",
    "content": "/*\r\n * $Id: RemoteSessionManager.java 642 2011-02-13 13:58:42Z catac $\r\n */\r\npackage lia.util.net.copy.gui;\r\n\r\nimport lia.util.net.common.Config;\r\nimport lia.util.net.common.ControlStream;\r\nimport lia.util.net.common.Utils;\r\nimport lia.util.net.copy.gui.session.Session;\r\nimport lia.util.net.copy.transport.CtrlMsg;\r\nimport lia.util.net.copy.transport.FDTProcolException;\r\nimport lia.util.net.copy.transport.gui.FileHandler;\r\nimport lia.util.net.copy.transport.gui.GUIControlChannel;\r\nimport lia.util.net.copy.transport.gui.GUIControlChannelNotifier;\r\nimport lia.util.net.copy.transport.gui.GUIMessage;\r\n\r\nimport javax.swing.*;\r\nimport java.awt.*;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\nimport java.util.Vector;\r\nimport java.util.concurrent.RunnableScheduledFuture;\r\nimport java.util.concurrent.TimeUnit;\r\n\r\n/**\r\n * The manager is responsable with sending and receiving commands\r\n * through the communication channel between the client and the server\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class RemoteSessionManager implements GUIControlChannelNotifier, Runnable {\r\n\r\n    private static final Object lock = new Object();\r\n    private static final long timeout = 3 * 1000L;\r\n    final ClientSessionManager clientSessionManager = new ClientSessionManager();\r\n    private final FDTPropsDialog props;\r\n    String hostname;\r\n    int port;\r\n    ConnectMonitor connd;\r\n    boolean initiated = false;\r\n    private FolderTable remoteTable;\r\n    private FolderTable localTable;\r\n    private GUIControlChannel channel;\r\n    private String workingDir;\r\n    private boolean canWrite;\r\n    private String userHome;\r\n    private String osName;\r\n    private String freeSpace;\r\n    private String fileSeparator;\r\n    private Vector<FileHandler> fileList;\r\n    private Exception remoteEx = null;\r\n    private String[] roots;\r\n    private boolean isRoot;\r\n    private HashMap<String, String> shortNames;\r\n    private Session localSession;\r\n    private Session remoteSession;\r\n    private JPanel p;\r\n    private RemoteSessionMonitor monitor;\r\n    private RunnableScheduledFuture remoteSessionTask;\r\n    private RunnableScheduledFuture monitorTask;\r\n\r\n    public RemoteSessionManager(FDTPropsDialog props, JPanel panel) {\r\n        this.props = props;\r\n        this.p = panel;\r\n    }\r\n\r\n    public void setSessions(Session localSession, Session remoteSession) {\r\n        this.localSession = localSession;\r\n        this.remoteSession = remoteSession;\r\n    }\r\n\r\n    /**\r\n     * Receives the current directory of the session.. (default user home)\r\n     */\r\n    public String getWorkingDirectory() {\r\n        return workingDir;\r\n    }\r\n\r\n    public String getFileSeparator() {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        if (fileSeparator == null) // problem occuring... ?\r\n            return System.getProperty(\"file.separator\");\r\n        return fileSeparator;\r\n    }\r\n\r\n    public boolean canWrite() {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        return canWrite;\r\n    }\r\n\r\n    /**\r\n     * Receives the directory home of the user\r\n     */\r\n    public String getUserHome() {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        return userHome;\r\n    }\r\n\r\n    /**\r\n     * Receives the name of the operating system\r\n     */\r\n    public String getOSName() {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        return osName;\r\n    }\r\n\r\n    /**\r\n     * Receives the amoung of free space\r\n     */\r\n    public String freeSpace() {\r\n        synchronized (lock) {\r\n            while (fileList == null || !initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        return freeSpace;\r\n    }\r\n\r\n    /**\r\n     * Return true if the current working directory is a root (no upper level)\r\n     */\r\n    public boolean isRoot() {\r\n        if (channel == null) return false;\r\n        try {\r\n            // send request...\r\n//\t\t\tCtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(5, null));\r\n//\t\t\tchannel.sendCtrlMessage(c);\r\n            synchronized (lock) {\r\n                while (fileList == null || !initiated) {\r\n                    try {\r\n                        lock.wait(timeout);\r\n                    } catch (Throwable t) {\r\n                    }\r\n                }\r\n            }\r\n            return isRoot;\r\n        } catch (Throwable t) {\r\n            return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Receives the list of current files and folder in the current directory of the session\r\n     */\r\n    public Vector<FileHandler> getFileList() {\r\n        synchronized (lock) {\r\n            while (fileList == null || !initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        return fileList;\r\n    }\r\n\r\n    public void removeFiles(String files[]) throws Exception {\r\n        if (channel == null) return;\r\n        fileList = null;\r\n        // send request\r\n        CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(10, files));\r\n        channel.sendCtrlMessage(c);\r\n        synchronized (lock) {\r\n            while (fileList == null) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable a) {\r\n                }\r\n            }\r\n        }\r\n        Exception tmpEx = remoteEx;\r\n        remoteEx = null;\r\n        if (tmpEx != null) {\r\n            throw tmpEx;\r\n        }\r\n    }\r\n\r\n    public void createDir(String name) throws Exception {\r\n        if (channel == null) return;\r\n        fileList = null;\r\n        // send request\r\n        CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(11, name));\r\n        channel.sendCtrlMessage(c);\r\n\r\n        synchronized (lock) {\r\n            while (fileList == null) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable a) {\r\n                }\r\n            }\r\n        }\r\n        Exception tmpEx = remoteEx;\r\n        remoteEx = null;\r\n        if (tmpEx != null) {\r\n            throw tmpEx;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory to an absolute pathname\r\n     */\r\n    public void setAbsoluteDir(String dir) throws Exception {\r\n        if (channel == null) return;\r\n        workingDir = null;\r\n        fileList = null;\r\n        // send request\r\n        CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(6, dir));\r\n        channel.sendCtrlMessage(c);\r\n        synchronized (lock) {\r\n            while (fileList == null) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable a) {\r\n                }\r\n            }\r\n        }\r\n        Exception tmpEx = remoteEx;\r\n        remoteEx = null;\r\n        if (tmpEx != null) {\r\n            throw tmpEx;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory to a relative to the current dir pathname\r\n     */\r\n    public void setRelativeDir(String dir) throws Exception {\r\n        if (channel == null) return;\r\n        workingDir = null;\r\n        fileList = null;\r\n        // send request\r\n        CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(7, dir));\r\n        channel.sendCtrlMessage(c);\r\n        synchronized (lock) {\r\n            while (fileList == null) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable a) {\r\n                }\r\n            }\r\n        }\r\n        Exception tmpEx = remoteEx;\r\n        remoteEx = null;\r\n        if (tmpEx != null) {\r\n            throw tmpEx;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Send the command to the other end to set the current working directory up one level\r\n     */\r\n    public void setUpDir() throws Exception {\r\n        if (channel == null) return;\r\n        workingDir = null;\r\n        fileList = null;\r\n        // send request\r\n        CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(8, null));\r\n        channel.sendCtrlMessage(c);\r\n        synchronized (lock) {\r\n            while (fileList == null) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable a) {\r\n                }\r\n            }\r\n        }\r\n        Exception tmpEx = remoteEx;\r\n        remoteEx = null;\r\n        if (tmpEx != null) {\r\n            throw tmpEx;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Receives the known root pathes of the remote FS\r\n     */\r\n    public String[] getRoots() {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        if (roots == null) {\r\n            roots = new String[]{\"\"};\r\n        }\r\n        return roots;\r\n    }\r\n\r\n    /**\r\n     * Receives the pathname denoted by a root folder (for the special case of links...)\r\n     */\r\n    public String getShortRootName(String rootFolder) {\r\n        synchronized (lock) {\r\n            while (!initiated) {\r\n                try {\r\n                    lock.wait(timeout);\r\n                } catch (Throwable t) {\r\n                }\r\n            }\r\n        }\r\n        if (rootFolder == null || shortNames == null || !shortNames.containsKey(rootFolder)) return null;\r\n        return shortNames.get(rootFolder);\r\n    }\r\n\r\n    /**\r\n     * Called to initiatilize a file transfer\r\n     */\r\n    public String initiateTransfer(String files[], boolean push, boolean isRecursive) {\r\n        String destDir = \".\";\r\n        if (push) {\r\n            if (!remoteSession.canWrite())\r\n                return \"Can not write to \" + remoteSession.getWorkingDir();\r\n            destDir = remoteSession.getWorkingDir();\r\n        } else {\r\n            if (!localSession.canWrite())\r\n                return \"Can not write to \" + localSession.getWorkingDir();\r\n            destDir = localSession.getWorkingDir();\r\n        }\r\n        return clientSessionManager.initTransfer(hostname, port, !push, files, destDir, props, isRecursive);\r\n    }\r\n\r\n    /**\r\n     * Called in order to interrogate on the status of the current transfer\r\n     */\r\n    public double getTransferPercent() {\r\n        return clientSessionManager.transferProgress();\r\n    }\r\n\r\n    public String getTransferSpeed() {\r\n        return clientSessionManager.currentSpeed();\r\n    }\r\n\r\n    /**\r\n     * Called in order to stop the current transfer\r\n     */\r\n    public void stopTransfer() {\r\n        clientSessionManager.cancelTransfer();\r\n        end();\r\n    }\r\n\r\n    public void end() {\r\n        clientSessionManager.end();\r\n    }\r\n\r\n    public void setCorrespondingPanel(FolderTable localTable, FolderTable remoteTable) {\r\n        this.localTable = localTable;\r\n        this.remoteTable = remoteTable;\r\n        if (channel != null) {\r\n            if (remoteTable != null)\r\n                remoteTable.setConnected(true);\r\n        }\r\n    }\r\n\r\n    public void run() {\r\n        connd.setProgress();\r\n    }\r\n\r\n    /**\r\n     * Called in order to construct the special FDTGui channel between the client and the server...\r\n     */\r\n    public void connect(final String hostName, final String user, final int port) {\r\n\r\n        if (connd == null)\r\n            connd = new ConnectMonitor(p);\r\n        remoteSessionTask = (RunnableScheduledFuture) Utils.getMonitoringExecService().scheduleWithFixedDelay(this, 1, 200, TimeUnit.MILLISECONDS);\r\n        connd.setVisible(true);\r\n\r\n        final RemoteSessionManager _instance = this;\r\n\r\n        new Thread(new Runnable() {\r\n            public void run() {\r\n                boolean auth = true;\r\n                if (user != null) {\r\n                    try {\r\n                        // initialize the config\r\n                        Map<String, Object> confMap = new HashMap<String, Object>();\r\n                        confMap.put(\"-p\", \"\" + port);\r\n                        confMap.put(\"SCPSyntaxUsed\", Boolean.TRUE);\r\n                        try {\r\n                            Config.initInstance(confMap);\r\n                        } catch (Throwable t1) {\r\n                            t1.printStackTrace();\r\n                        }\r\n\r\n                        // try to authenticate...\r\n                        ControlStream sshConn = new GUISSHControlStream(hostName, user, connd);\r\n                        sshConn.connect();\r\n\r\n                        // start remote fdt\r\n                        Config config = Config.getInstance();\r\n                        String localAddresses = config.getLocalAddresses();\r\n                        // append the required options to the configurable java\r\n                        // command\r\n                        String remoteCmd = config.getRemoteCommand() + \" -p \" + config.getPort() + \" -silent -S -f \" + localAddresses;\r\n                        String remoteCustomShell = config.getCustomShell();\r\n                        System.err.println(\" [ CONFIG ] Starting FDT server over SSH using [ \" + remoteCmd + \" ]\");\r\n                        sshConn.startProgram(remoteCmd, remoteCustomShell);\r\n                        sshConn.waitForControlMessage(\"READY\");\r\n                        System.err.println(\" [ CONFIG ] FDT server successfully started on [ \" + config.getHostName() + \" ]\");\r\n\r\n                        auth = true;\r\n                    } catch (Throwable t) {\r\n                        channel = null;\r\n                        initiated = true;\r\n                        auth = false;\r\n                    }\r\n                }\r\n                if (auth) {\r\n                    try {\r\n                        if (channel != null)\r\n                            channel.close(\"New connection\", null);\r\n                        channel = new GUIControlChannel(hostName, port, _instance);\r\n                        new Thread(channel, \"GUI Control channel for [ \" + hostName + \":\" + port + \" ]\").start();\r\n                        if (remoteTable != null)\r\n                            remoteTable.setConnected(true);\r\n                        _instance.hostname = hostName;\r\n                        _instance.port = port;\r\n                        Utils.getMonitoringExecService().remove(remoteSessionTask);\r\n                        Utils.getMonitoringExecService().purge();\r\n                        connd.setVisible(false);\r\n                        monitor = new RemoteSessionMonitor();\r\n                        monitorTask = (RunnableScheduledFuture) Utils.getMonitoringExecService().scheduleWithFixedDelay(monitor, 1, 500, TimeUnit.MILLISECONDS);\r\n                        return;\r\n                    } catch (Throwable t) {\r\n                        try {\r\n                            channel.close(t.getLocalizedMessage(), t);\r\n                        } catch (Throwable tt) {\r\n                        }\r\n                        channel = null;\r\n                        t.printStackTrace();\r\n                        initiated = true;\r\n                    }\r\n                }\r\n                Utils.getMonitoringExecService().remove(remoteSessionTask);\r\n                Utils.getMonitoringExecService().purge();\r\n                connd.setVisible(false);\r\n                if (remoteTable != null)\r\n                    remoteTable.setConnected(false);\r\n            }\r\n        }).start();\r\n    }\r\n\r\n    private void process(GUIMessage msg) {\r\n        switch (msg.getMID()) {\r\n            case 0: // current working dir\r\n            {\r\n                Object o[] = (Object[]) msg.getMsg();\r\n                workingDir = (String) o[0];\r\n                canWrite = (Boolean) o[1];\r\n                break;\r\n            }\r\n            case 1: // user home\r\n            {\r\n                userHome = (String) msg.getMsg();\r\n                break;\r\n            }\r\n            case 2: // os name\r\n            {\r\n                osName = (String) msg.getMsg();\r\n                break;\r\n            }\r\n            case 3: // current files\r\n            {\r\n                fileList = (Vector<FileHandler>) msg.getMsg();\r\n                remoteEx = msg.getException();\r\n                break;\r\n            }\r\n            case 4: // current roots\r\n            {\r\n                roots = (String[]) msg.getMsg();\r\n                break;\r\n            }\r\n            case 5: // is root\r\n            {\r\n                isRoot = ((Boolean) msg.getMsg()).booleanValue();\r\n                break;\r\n            }\r\n            case 9: // short name\r\n            {\r\n                shortNames = (HashMap<String, String>) msg.getMsg();\r\n                break;\r\n            }\r\n            case 10: // file separator\r\n            {\r\n                fileSeparator = (String) msg.getMsg();\r\n                break;\r\n            }\r\n            case 11: // end of init\r\n            {\r\n                initiated = true;\r\n//\t\t\tsynchronized (lock) {\r\n//\t\t\t\tlock.notifyAll();\r\n//\t\t\t}\r\n                break;\r\n            }\r\n            case 12: // freeSpace\r\n            {\r\n                freeSpace = (String) msg.getMsg();\r\n                break;\r\n            }\r\n        }\r\n        synchronized (lock) {\r\n            lock.notifyAll();\r\n        }\r\n    }\r\n\r\n    public void sendMessage(GUIMessage msg) throws Exception {\r\n        if (channel != null) {\r\n            CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, msg);\r\n            channel.sendCtrlMessage(c);\r\n        }\r\n    }\r\n\r\n    public boolean isConnected() {\r\n        return channel != null;\r\n    }\r\n\r\n    public void notifyCtrlMsg(GUIControlChannel controlChannel, Object o) throws FDTProcolException {\r\n        if (o == null) return;\r\n        if (o instanceof GUIMessage) {\r\n            process((GUIMessage) o);\r\n            return;\r\n        }\r\n        if (!(o instanceof CtrlMsg)) return;\r\n        CtrlMsg msg = (CtrlMsg) o;\r\n        if (msg.tag != CtrlMsg.GUI_MSG) return; // only this type of message can be processed here\r\n        process((GUIMessage) msg.message);\r\n    }\r\n\r\n    public void notifyCtrlSessionDown(GUIControlChannel controlChannel, Throwable cause) throws FDTProcolException {\r\n        if (remoteTable != null)\r\n            remoteTable.setConnected(false);\r\n    }\r\n\r\n    public FolderTable getLocalTable() {\r\n        return localTable;\r\n    }\r\n\r\n    public FolderTable getRemoteTable() {\r\n        return remoteTable;\r\n    }\r\n\r\n    public static class ConnectMonitor extends JDialog {\r\n\r\n        private JProgressBar progress;\r\n        private JLabel label;\r\n\r\n        public ConnectMonitor(JPanel component) {\r\n            super();\r\n            JDialog.setDefaultLookAndFeelDecorated(true);\r\n            setLocation((int) component.getLocationOnScreen().getX() + component.getWidth() / 2 - 160, (int) component.getLocationOnScreen().getY() + component.getHeight() / 2 - 62);\r\n            setTitle(\"Connecting\");\r\n            setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);\r\n            setAlwaysOnTop(true);\r\n            setDefaultLookAndFeelDecorated(true);\r\n            getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));\r\n            JPanel p1 = new JPanel();\r\n            p1.setLayout(new BorderLayout());\r\n            label = new JLabel(\"Connecting\");\r\n            p1.add(label, BorderLayout.CENTER);\r\n            getContentPane().add(p1);\r\n            JPanel p2 = new JPanel();\r\n            p2.setLayout(new BorderLayout());\r\n            progress = new JProgressBar();\r\n            progress.setIndeterminate(true);\r\n//\t\t\tprogress.setUI(new ProgressBarUI());\r\n            progress.setStringPainted(false);\r\n            p2.add(progress, BorderLayout.CENTER);\r\n            getContentPane().add(p2);\r\n            setSize(240, 75);\r\n            setResizable(false);\r\n        }\r\n\r\n        public void setProgress() {\r\n            this.progress.setValue((this.progress.getValue() + 1) % 100);\r\n            this.progress.repaint();\r\n        }\r\n\r\n        public void setVisible(boolean visible) {\r\n            if (visible)\r\n                progress.setValue(0);\r\n            super.setVisible(visible);\r\n        }\r\n    }\r\n\r\n    private class RemoteSessionMonitor implements Runnable {\r\n\r\n        public RemoteSessionMonitor() {\r\n        }\r\n\r\n        public void run() {\r\n//\t\t\tThread.currentThread().setName(\"RemoteSessionMonitor[GUI]\");\r\n            if (channel == null || channel.isClosed()) {\r\n                System.out.println(\"Detected connection closed...\");\r\n                initiated = true;\r\n                synchronized (lock) {\r\n                    lock.notifyAll(); // force awake\r\n                }\r\n                try {\r\n                    Utils.getMonitoringExecService().remove(remoteSessionTask);\r\n                    Utils.getMonitoringExecService().purge();\r\n                } catch (Throwable t) {\r\n                }\r\n                if (connd != null)\r\n                    connd.setVisible(false);\r\n                if (remoteTable != null)\r\n                    remoteTable.setConnected(false);\r\n                if (monitor != null) {\r\n                    Utils.getMonitoringExecService().remove(monitorTask);\r\n                    Utils.getMonitoringExecService().purge();\r\n                    monitor = null;\r\n                }\r\n                try {\r\n                    channel.close(\"Closed from the other end\", new Exception());\r\n                } catch (Throwable tt) {\r\n                }\r\n                channel = null;\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/StatusBar.java",
    "content": "/*\n * $Id: StatusBar.java 454 2007-10-08 15:52:49Z cipsm $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport javax.swing.text.*;\nimport javax.swing.text.html.HTML.*;\nimport javax.swing.text.html.*;\nimport java.awt.*;\nimport java.awt.datatransfer.*;\nimport java.awt.event.*;\nimport java.util.Enumeration;\nimport java.util.LinkedList;\n\n/**\n * The status bar class\n *\n * @author Ciprian Dobre\n */\npublic class StatusBar extends JTextPane implements ClipboardOwner, Runnable {\n\n    private static final Object lock = new Object();\n    static String nl = \"\\n\";\n    private final LinkedList<String> currentLines = new LinkedList<String>();\n    private final StatusBar _instance;\n    private String lastLine = \"\";\n    private JScrollPane pane;\n    private JTextPane p1;\n    private boolean redoCalled = false;\n\n    public StatusBar(final JScrollPane pane) {\n        super();\n        this.pane = pane;\n        pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);\n        setOpaque(true);\n        setToolTipText(\"Status bar\");\n        setBackground(Color.white);\n        setContentType(\"text/html\");\n\n        p1 = new JTextPane();\n        p1.setOpaque(true);\n        p1.setToolTipText(\"Status bar\");\n        p1.setBackground(Color.white);\n        p1.setContentType(\"text/html\");\n\n        final StatusBar textArea = this;\n\n        textArea.addMouseListener(new MouseAdapter() {\n            public void mouseClicked(MouseEvent e) {\n                if (SwingUtilities.isRightMouseButton(e)) {\n                    try {\n                        int offset = viewToModel(e.getPoint());\n                        int rowStart = Utilities.getRowStart(textArea, offset);\n                        int rowEnd = Utilities.getRowEnd(textArea, offset);\n                        synchronized (getTreeLock()) {\n                            textArea.select(rowStart, rowEnd);\n                        }\n                    } catch (Exception e2) {\n                    }\n                }\n            }\n        });\n\n        textArea.addKeyListener(new KeyAdapter() {\n            public void keyPressed(KeyEvent e) {\n                if (e.getKeyCode() == KeyEvent.VK_C && e.isControlDown()) { // copy\n                    setClipboardContents(textArea.getSelectedText());\n                }\n            }\n        });\n//\t\tUtils.getMonitoringExecService().scheduleWithFixedDelay(this, 1, 500, TimeUnit.MILLISECONDS);\n        _instance = this;\n        (new Thread(this)).start();\n    }\n\n    /**\n     * Place a String on the clipboard, and make this class the\n     * owner of the Clipboard's contents.\n     */\n    public void setClipboardContents(String aString) {\n        StringSelection stringSelection = new StringSelection(aString);\n        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();\n        clipboard.setContents(stringSelection, this);\n    }\n\n    public synchronized void addText(String text) {\n        if (text == null)\n            return;\n        synchronized (currentLines) {\n            while (true) {\n                int index = text.indexOf(nl);\n                if (index >= 0) {\n                    String str = text.substring(0, index);\n                    if (lastLine.length() != 0) {\n                        str = lastLine + str;\n                        lastLine = \"\";\n                    }\n                    currentLines.addLast(str);\n                    if (currentLines.size() > 100)\n                        currentLines.removeFirst();\n                    text = text.substring(index + nl.length());\n                } else {\n                    if (text.length() != 0) {\n                        lastLine = lastLine + text;\n                    }\n                    break;\n                }\n            }\n        }\n        synchronized (lock) {\n            redoCalled = true;\n            lock.notifyAll();\n        }\n    }\n\n    public void run() {\n        Thread.currentThread().setName(\"[FDT StatusThread]\");\n        while (true) {\n            synchronized (lock) {\n                while (!redoCalled) {\n                    try {\n                        lock.wait();\n                    } catch (Exception e) {\n                    }\n                }\n                redoCalled = false;\n            }\n            redo();\n        }\n    }\n\n    private void redo() {\n        StringBuffer buf = new StringBuffer();\n        boolean first = true;\n        synchronized (currentLines) {\n            buf.append(\"<html>\");\n            for (String t : currentLines) {\n                if (!first) buf.append(\"<br>\");\n                buf.append(t);\n                first = false;\n            }\n            if (lastLine.length() != 0) {\n                if (!first) buf.append(\"<br>\");\n                buf.append(lastLine);\n            }\n            buf.append(\"</html>\");\n        }\n\n        p1.setText(buf.toString());\n        synchronized (getTreeLock()) {\n            try {\n                setEditorKit(p1.getEditorKit());\n                setDocument(p1.getDocument());\n                pane.getViewport().scrollRectToVisible(new Rectangle(0, _instance.getPreferredSize().height, 0, 0));\n            } catch (Throwable t) {\n            }\n        }\n        _instance.repaint();\n        p1 = new JTextPane();\n        p1.setOpaque(true);\n        p1.setToolTipText(\"Status bar\");\n        p1.setBackground(Color.white);\n        p1.setContentType(\"text/html\");\n    }\n\n    /**\n     * Empty implementation of the ClipboardOwner interface.\n     */\n    public void lostOwnership(Clipboard aClipboard, Transferable aContents) {\n        //do nothing\n    }\n\n    public String getSelectedText() {\n        return getSelectedHTMLAsText();\n    }\n\n    public String getSelectedHTMLAsText() {\n        String text = super.getSelectedText();\n        if (text == null || text.length() == 0) {\n            return text;\n        }\n\n        int startPos = getSelectionStart();\n        int endPos = getSelectionEnd();\n\n        int selectedCharacters = endPos - startPos;\n        StringBuffer buffer = new StringBuffer(selectedCharacters);\n        int nbspCount = 0;\n        for (int i = 0, j = startPos; i < selectedCharacters; i++, j++) {\n            Element element1 = ((HTMLDocument) getDocument()).getCharacterElement(j);\n            if (isReplaceWithNewLine(element1)) {\n                buffer.append('\\n');\n            } else {\n\n                buffer.append(text.charAt(i));\n            }\n\n        }\n        return buffer.toString();\n    }\n\n    private boolean isReplaceWithNewLine(Element element1) {\n        AttributeSet as1 = element1.getAttributes();\n        Enumeration attribEntriesOriginal1 = as1.getAttributeNames();\n        while (attribEntriesOriginal1.hasMoreElements()) {\n            Object entryKey = attribEntriesOriginal1.nextElement();\n            Object entryValue = as1.getAttribute(entryKey);\n\n            if (entryValue instanceof Tag) {\n                if (entryValue == Tag.BR) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n} // end of class StatusBar\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/TransferMonitor.java",
    "content": "/*\n * $Id: TransferMonitor.java 462 2007-10-09 15:28:58Z cipsm $\n */\npackage lia.util.net.copy.gui;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.awt.event.*;\nimport java.text.NumberFormat;\nimport java.util.Locale;\n\n//import lia.util.net.common.Utils;\n\n/**\n * @author Ciprian Dobre\n */\npublic class TransferMonitor implements Runnable {\n\n    private static final Object lock = new Object();\n    private static final NumberFormat nf = NumberFormat.getInstance(Locale.US);\n\n    static {\n        nf.setMaximumFractionDigits(2);\n    }\n\n    private final RemoteSessionManager manager;\n    private final TransferMonitor _instance;\n    private ProgressMonitor progressMonitor;\n    private boolean push;\n    private boolean toRun = false;\n    private boolean workInProgress = false;\n\n    public TransferMonitor(final JPanel ft, boolean push, final RemoteSessionManager manager) {\n        this.push = push;\n        this.manager = manager;\n        progressMonitor = new ProgressMonitor(ft, \"Initializing...\", 0, 100);\n        ft.setEnabled(true);\n        UIManager.put(\"ProgressBar.foreground\", new Color(8, 32, 128));\n        _instance = this;\n        (new Thread(this)).start();\n    }\n\n    public static void main(String args[]) {\n        ProgressMonitor m = new ProgressMonitor(new JPanel(), \"Init\", 0, 100);\n        for (int i = 0; i < 100; i++) {\n            m.setProgress(i);\n            m.setNote(\"<html>Transfer is \" + nf.format(i) + \"% complete<br>Transfer rate is \" + i + \"</html>\");\n            try {\n                Thread.sleep(100);\n            } catch (Exception e) {\n            }\n        }\n    }\n\n    public void restart(final JPanel ft, boolean push) {\n        this.push = push;\n        progressMonitor.setProgress(0);\n        progressMonitor.setNote(\"Initializing...\");\n//\t\tif (progressMonitor != null) { progressMonitor.close(); progressMonitor = null; }\n//\t\tprogressMonitor = new ProgressMonitor(ft, \"Initializing...\", 0, 100);\n//\t\tft.setEnabled(true);\n    }\n\n    public void start() {\n        progressMonitor.setVisible(true);\n        synchronized (lock) {\n            toRun = true;\n            lock.notifyAll();\n        }\n    }\n\n    public boolean finished() {\n        synchronized (lock) {\n            return toRun == false && workInProgress == false;\n        }\n    }\n\n    public void run() {\n\n        Thread.currentThread().setName(\"[FDT TransferMonitorThread]\");\n        while (true) {\n            synchronized (lock) {\n                while (!toRun) {\n                    try {\n                        lock.wait();\n                    } catch (Exception e) {\n                    }\n                }\n                toRun = false;\n                workInProgress = true;\n            }\n\n            while (true) {\n                if (manager == null) {\n                    progressMonitor.close();\n                    break;\n                }\n                if (progressMonitor.isCanceled()) {\n                    System.out.println(\"cancelled\");\n                    progressMonitor.close();\n                    manager.stopTransfer();\n                    break;\n                }\n                double progress = manager.getTransferPercent();\n                if (Double.isNaN(progress) || Double.isInfinite(progress)) {\n                    progressMonitor.close();\n                    manager.end();\n                    break;\n                }\n                double val = Math.min(100.0, progress);\n//\t\t\t\tSystem.out.println(val);\n                if (val >= 100.0) {\n                    progressMonitor.close();\n                    if (push) {\n                        if (manager != null && manager.getRemoteTable() != null)\n                            manager.getRemoteTable().setConnected(true);\n                        manager.getLocalTable().getTable().requestFocusInWindow();\n                    } else {\n                        if (manager != null && manager.getLocalTable() != null) {\n                            manager.getLocalTable().setConnected(true);\n                        }\n                        manager.getRemoteTable().getTable().requestFocusInWindow();\n                    }\n                    manager.end();\n                    break;\n                }\n                if (!Double.isInfinite(val) && !Double.isNaN(val)) {\n                    progressMonitor.setProgress((int) val);\n                    progressMonitor.setNote(\"<html>Transfer is \" + nf.format(val) + \"% complete<br>Transfer rate is \" + manager.getTransferSpeed() + \"</html>\");\n                }\n                try {\n                    Thread.sleep(200);\n                } catch (Exception e) {\n                }\n            }\n            synchronized (lock) {\n                workInProgress = false;\n            }\n        }\n    }\n\n    public static class ProgressMonitor extends JDialog {\n\n        private JProgressBar progress;\n        private JLabel label;\n        private JButton cancel;\n        private boolean isCancelled = false;\n\n        public ProgressMonitor(JPanel component, String text, int min, int max) {\n            super();\n            JDialog.setDefaultLookAndFeelDecorated(true);\n            setLocation((int) component.getLocationOnScreen().getX() + component.getWidth() / 2 - 160, (int) component.getLocationOnScreen().getY() + component.getHeight() / 2 - 62);\n            setTitle(\"Copying\");\n            setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);\n            setAlwaysOnTop(true);\n            setDefaultLookAndFeelDecorated(true);\n            getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));\n            JPanel p1 = new JPanel();\n            p1.setLayout(new BorderLayout());\n            label = new JLabel(text);\n            p1.add(label, BorderLayout.CENTER);\n            getContentPane().add(p1);\n            JPanel p2 = new JPanel();\n            p2.setLayout(new BorderLayout());\n            progress = new JProgressBar(min, max);\n            progress.setUI(new ProgressBarUI());\n            progress.setStringPainted(false);\n            p2.add(progress, BorderLayout.CENTER);\n            getContentPane().add(p2);\n            JPanel p3 = new JPanel();\n            p3.setLayout(new BoxLayout(p3, BoxLayout.X_AXIS));\n            cancel = new JButton(\"Cancel\");\n            cancel.addActionListener(new ActionListener() {\n                public void actionPerformed(ActionEvent e) {\n                    isCancelled = true;\n                    setVisible(false);\n                }\n            });\n            p3.add(cancel);\n            getContentPane().add(Box.createVerticalStrut(3));\n            getContentPane().add(p3);\n            getContentPane().add(Box.createVerticalStrut(3));\n            setSize(320, 125);\n            setResizable(false);\n        }\n\n        public void close() {\n            isCancelled = false;\n            setVisible(false);\n        }\n\n        public boolean isCanceled() {\n            return isCancelled;\n        }\n\n        public void setProgress(int progress) {\n            this.progress.setValue(progress);\n            this.progress.repaint();\n        }\n\n        public void setNote(String note) {\n            label.setText(note);\n            label.repaint();\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/session/LocalSession.java",
    "content": "/*\r\n * $Id: LocalSession.java 473 2007-10-10 10:23:18Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui.session;\r\n\r\nimport javax.swing.filechooser.*;\r\nimport java.io.File;\r\nimport java.util.*;\r\n\r\n/**\r\n * The LocalSession represents the session on which the client is running\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class LocalSession extends Session {\r\n\r\n    private static FileSystemView local = FileSystemView.getFileSystemView();\r\n    // helper mapping between display names and real File folders used for root folders\r\n    private final HashMap<String, File> roots = new HashMap<String, File>();\r\n    /**\r\n     * The current working directory\r\n     */\r\n    public String currentDir;\r\n    /**\r\n     * The default directory of the user\r\n     */\r\n    public String userDir;\r\n\r\n    /**\r\n     * The name of the operating system\r\n     */\r\n    public String osName;\r\n    private boolean canWrite = true;\r\n    private File currentFile;\r\n\r\n    public LocalSession() {\r\n        currentFile = local.getHomeDirectory();\r\n        this.currentDir = currentFile.getAbsolutePath();\r\n        osName = System.getProperty(\"os.name\");\r\n        userDir = System.getProperty(\"user.home\");\r\n        update();\r\n//\t\tSystem.out.println(currentDir);\r\n    }\r\n\r\n    public static void main(String args[]) {\r\n\r\n/*\t\tFile roots[] = local.getRoots();\r\n\t\tfor (int i=0; i<roots.length; i++) {\r\n\t\t\tSystem.out.println(\"'\"+local.getSystemDisplayName(roots[i])+\"'\"+local.getSystemTypeDescription(roots[i])+\"'\"+local.getSystemDisplayName(roots[i]).length());\r\n\t\t}\r\n\t\tSystem.out.println(\"....\");\r\n\t\troots = File.listRoots();\r\n\t    for (int i=0; i<roots.length; i++) {\r\n\t\t\tSystem.out.println(\"'\"+local.getSystemDisplayName(roots[i])+\"'\"+local.getSystemTypeDescription(roots[i])+\"'\"+local.getSystemDisplayName(roots[i]).length());\r\n\t    } */\r\n\r\n        File f = new File(\"E:\\\\cipsm\");\r\n        f = local.getChild(f, \"..\");\r\n//\t\tFile roots[] = local.getRoots();\r\n//\t\tFile f = roots[0];\r\n//\t\tSystem.out.println(local.isDrive(f));\r\n//\t\tf = local.getChild(f, \"My Computer\");\r\n//\t\tSystem.out.println(f.isDirectory());\r\n//\t\tSystem.out.println(local.isTraversable(f));\r\n//\t\tf = local.getParentDirectory(f);\r\n//\t\tSystem.out.println(local.isRoot(f));\r\n        File roots[] = local.getFiles(f, false);\r\n        for (int i = 0; i < roots.length; i++) {\r\n            System.out.println(roots[i].isDirectory() + \"'\" + local.getSystemDisplayName(roots[i]) + \"'\" + local.getSystemTypeDescription(roots[i]) + \"'\" + local.getSystemDisplayName(roots[i]).length());\r\n        }\r\n        System.out.println(\"....\");\r\n        roots = f.listFiles();\r\n        for (int i = 0; i < roots.length; i++) {\r\n            System.out.println(\"'\" + local.getSystemDisplayName(roots[i]) + \"'\" + local.getSystemTypeDescription(roots[i]) + \"'\" + local.getSystemDisplayName(roots[i]).length());\r\n        }\r\n    }\r\n\r\n    public void setAbsoluteDir(String dir) {\r\n        if (dir == null) return;\r\n        dir = getRoot(dir);\r\n        if (roots.containsKey(dir)) {\r\n            currentFile = roots.get(dir);\r\n            currentDir = currentFile.getAbsolutePath();\r\n            update();\r\n            return;\r\n        }\r\n        try {\r\n            File f = new File(dir);\r\n            if (!f.exists() || !f.isDirectory() || !f.canRead()) return;\r\n            currentFile = f;\r\n            currentDir = currentFile.getAbsolutePath();\r\n            update();\r\n        } catch (Exception e) {\r\n        }\r\n    }\r\n\r\n    private final String getRoot(String dir) {\r\n        if (roots.containsKey(dir)) return dir;\r\n        for (Map.Entry<String, File> entry : roots.entrySet()) {\r\n            if (entry.getValue().getAbsolutePath().equals(dir)) return entry.getKey();\r\n        }\r\n        return dir;\r\n    }\r\n\r\n    public void setRelativeDir(String dir) {\r\n        File f = local.getChild(currentFile, dir);\r\n        if (f == null || !f.exists() || !f.isDirectory()) return; // error, cannot change\r\n        currentFile = f;\r\n        currentDir = f.getAbsolutePath();\r\n        update();\r\n    }\r\n\r\n    public void setUpDir() {\r\n        File f = local.getParentDirectory(currentFile);\r\n        if (f == null || !f.exists() || !f.isDirectory()) return; // error, cannot change\r\n        currentFile = f;\r\n        currentDir = f.getAbsolutePath();\r\n        update();\r\n    }\r\n\r\n    public String[] getRoots() {\r\n        roots.clear(); // clear the previously discovered roots\r\n        // auxiliary hash used\r\n        final HashSet<String> h = new HashSet<String>();\r\n        // start by using the FileSystemView...\r\n        File roots[] = local.getRoots();\r\n        if (roots != null) {\r\n            for (int i = 0; i < roots.length; i++) {\r\n                String displayName = local.getSystemDisplayName(roots[i]);\r\n                if (h.contains(displayName)) continue; // do not add it twice\r\n                if (displayName.length() == 0)\r\n                    continue; // skip empty drives (it applies to cd drives and floppy drives without media\r\n                h.add(displayName);\r\n//\t\t\t\tString description = local.getSystemTypeDescription(roots[i]);\r\n//\t\t\t\tif (description.length() != 0) {\r\n//\t\t\t\t\tdisplayName += \" \"+description;\r\n//\t\t\t\t}\r\n                this.roots.put(displayName, roots[i]);\r\n            }\r\n        }\r\n        // then use the File object....\r\n        roots = File.listRoots();\r\n        if (roots != null) {\r\n            for (int i = 0; i < roots.length; i++) {\r\n                String displayName = local.getSystemDisplayName(roots[i]);\r\n                if (h.contains(displayName)) continue; // do not add it twice\r\n                if (displayName.length() == 0)\r\n                    continue; // skip empty drives (it applies to cd drives and floppy drives without media\r\n                h.add(displayName);\r\n//\t\t\t\tString description = local.getSystemTypeDescription(roots[i]);\r\n//\t\t\t\tif (description.length() != 0) {\r\n//\t\t\t\t\tdisplayName += \" \"+description;\r\n//\t\t\t\t}\r\n                this.roots.put(displayName, roots[i]);\r\n            }\r\n        }\r\n        // also if linux put the path to the home directory...\r\n        if (System.getProperty(\"os.name\").toLowerCase(Locale.US).contains(\"linux\")) {\r\n            String p = System.getProperty(\"user.home\");\r\n            File f = new File(p);\r\n            if (f.exists()) {\r\n                File pa = null;\r\n                while ((pa = f.getParentFile()) != null && pa.exists()) {\r\n                    this.roots.put(f.getAbsolutePath(), f);\r\n                    f = pa;\r\n                }\r\n            }\r\n        }\r\n        final String[] keys = new String[this.roots.size()];\r\n        int i = 0;\r\n        for (Iterator<String> it = this.roots.keySet().iterator(); it.hasNext() && i < keys.length; i++) {\r\n            keys[i] = it.next();\r\n        }\r\n        return keys;\r\n    }\r\n\r\n    public String getShortRootName(String rootFolder) {\r\n        if (rootFolder == null) return null;\r\n        rootFolder = getRoot(rootFolder);\r\n        if (roots.containsKey(rootFolder)) return roots.get(rootFolder).getAbsolutePath();\r\n        return null;\r\n    }\r\n\r\n    public boolean isRoot() {\r\n        if (local.isDrive(currentFile)) {\r\n            return true;\r\n        }\r\n        File f = local.getParentDirectory(currentFile);\r\n        return f == null;\r\n    }\r\n\r\n    private void update() { // updates the current working directory\r\n\r\n        // clear the current known properties....\r\n        dirs.clear();\r\n        length.clear();\r\n        icons.clear();\r\n        modif.clear();\r\n        read.clear();\r\n        write.clear();\r\n        // list the current files\r\n        File l[] = local.getFiles(currentFile, false);\r\n\r\n//\t\tSystem.out.println(currentFile.getUsableSpace());\r\n\r\n        if (l != null) {\r\n            for (int i = 0; i < l.length; i++) {\r\n                String fn = local.getSystemDisplayName(l[i]);\r\n                if (fn.length() == 0) continue;\r\n                if (l[i].isDirectory()) {\r\n                    // check to see if we are not looking at some links...\r\n                    try {\r\n                        File tmpf = local.getChild(currentFile, fn);\r\n                        if (tmpf == null || !local.isTraversable(tmpf)) continue; // alarm, link detected here\r\n                        local.getFiles(tmpf, false);\r\n                    } catch (Throwable t) {\r\n                        continue;\r\n                    }\r\n                    // otherwise is ok to add it...\r\n                    dirs.add(fn);\r\n                    icons.put(fn, local.getSystemIcon(l[i]));\r\n                    modif.put(fn, l[i].lastModified());\r\n                    read.put(fn, l[i].canRead());\r\n                    write.put(fn, l[i].canWrite());\r\n                } else if (l[i].isFile()) {\r\n                    length.put(fn, l[i].length());\r\n                    icons.put(fn, local.getSystemIcon(l[i]));\r\n                    modif.put(fn, l[i].lastModified());\r\n                    read.put(fn, l[i].canRead());\r\n                    write.put(fn, l[i].canWrite());\r\n                }\r\n            }\r\n        }\r\n        try {\r\n            int i = 0;\r\n            while (true) {\r\n                File f = new File(currentDir + System.getProperty(\"file.separator\") + \"fdt\" + i);\r\n                if (f.exists()) continue;\r\n                f.createNewFile();\r\n                canWrite = f.exists();\r\n                if (canWrite)\r\n                    f.delete();\r\n                break;\r\n            }\r\n        } catch (Throwable t) {\r\n            canWrite = false;\r\n        }\r\n    }\r\n\r\n    public String getFileSeparator() {\r\n        return System.getProperty(\"file.separator\");\r\n    }\r\n\r\n    public String getWorkingDir() {\r\n        return currentDir;\r\n    }\r\n\r\n    public boolean canWrite() {\r\n        return canWrite;\r\n    }\r\n\r\n    public String getOSName() {\r\n        return osName;\r\n    }\r\n\r\n    public String getUserDir() {\r\n        return userDir;\r\n    }\r\n\r\n    public boolean fileExists(String fileName) {\r\n        if (fileName == null) return false;\r\n        return modif.containsKey(fileName);\r\n    }\r\n\r\n    public void removeFiles(String[] files) {\r\n        if (files == null) return;\r\n        for (int i = 0; i < files.length; i++) {\r\n            try {\r\n                File f = new File(files[i]);\r\n                if (f.isDirectory()) {\r\n                    File ff[] = f.listFiles();\r\n                    if (ff != null) {\r\n                        String str[] = new String[ff.length];\r\n                        for (int j = 0; j < str.length; j++) {\r\n                            str[j] = ff[j].getAbsolutePath();\r\n                        }\r\n                        removeFiles(str);\r\n                    }\r\n                }\r\n                f.delete();\r\n            } catch (Throwable t) {\r\n            }\r\n        }\r\n        update();\r\n    }\r\n\r\n    public void createDir(String name) {\r\n        try {\r\n            File f = new File(name);\r\n            f.mkdirs();\r\n        } catch (Throwable t) {\r\n        }\r\n        update();\r\n    }\r\n\r\n    public String freeSpace() {\r\n        if (currentFile == null) return null;\r\n        try {\r\n            long space = currentFile.getFreeSpace();\r\n            return parseSize(space);\r\n        } catch (Throwable t) {\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private final String parseSize(long space) {\r\n        if (space > 1024l) {\r\n            space = space / 1024l;\r\n            if (space > 1024l) {\r\n                space = space / 1024l;\r\n                if (space > 1024l) {\r\n                    space = space / 1024l;\r\n                    if (space > 1024l) {\r\n                        space = space / 1024l;\r\n                        return space + \" TB\";\r\n                    } else\r\n                        return space + \" GB\";\r\n                } else\r\n                    return space + \" MB\";\r\n            } else\r\n                return space + \"KB\";\r\n        } else {\r\n            return space + \" B\";\r\n        }\r\n    }\r\n\r\n} // end of class LocalSession\r\n\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/session/RemoteSession.java",
    "content": "/*\r\n * $Id: RemoteSession.java 530 2009-06-04 13:38:13Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui.session;\r\n\r\nimport lia.util.net.copy.gui.RemoteSessionManager;\r\nimport lia.util.net.copy.transport.gui.FileHandler;\r\n\r\nimport javax.swing.*;\r\nimport javax.swing.filechooser.*;\r\nimport java.io.File;\r\nimport java.net.URL;\r\nimport java.util.HashMap;\r\nimport java.util.Locale;\r\nimport java.util.Vector;\r\n\r\n/**\r\n * The RemoteSession represents the session with which the client is communicating\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic class RemoteSession extends Session {\r\n\r\n    public static final Icon folderIcon;\r\n    // mapping between extensions and associated known icons..\r\n    public static final HashMap<String, Icon> icons = new HashMap<String, Icon>();\r\n\r\n//\tprivate String workingDir;\r\n//\tprivate boolean root = false;\r\n    final static String osName = System.getProperty(\"os.name\").toLowerCase(Locale.US);\r\n    private static final FileSystemView local = FileSystemView.getFileSystemView();\r\n\r\n    static {\r\n        folderIcon = local.getSystemIcon(new File(System.getProperty(\"user.dir\")));\r\n    }\r\n\r\n    private final RemoteSessionManager manager;\r\n    private ImageIcon unknownIcon;\r\n\r\n    public RemoteSession(RemoteSessionManager manager) {\r\n        this.manager = manager;\r\n    }\r\n\r\n    private static final boolean isWindows() {\r\n        return osName.indexOf(\"windows\") > -1;\r\n    }\r\n\r\n    private static final boolean isLinux() {\r\n        return osName.indexOf(\"linux\") > -1;\r\n    }\r\n\r\n    private static final boolean isMac() {\r\n        return osName.indexOf(\"mac\") > -1;\r\n    }\r\n\r\n    public void setAbsoluteDir(String dir) throws Exception {\r\n        manager.setAbsoluteDir(dir);\r\n        update();\r\n    }\r\n\r\n    public void setRelativeDir(String dir) throws Exception {\r\n        manager.setRelativeDir(dir);\r\n        update();\r\n    }\r\n\r\n    public void setUpDir() throws Exception {\r\n        manager.setUpDir();\r\n        update();\r\n    }\r\n\r\n    public String[] getRoots() throws Exception {\r\n        return manager.getRoots();\r\n    }\r\n\r\n    public String getFileSeparator() {\r\n        return manager.getFileSeparator();\r\n    }\r\n\r\n    public String getShortRootName(String rootFolder) {\r\n        return manager.getShortRootName(rootFolder);\r\n    }\r\n\r\n    public boolean isRoot() {\r\n        return manager.isRoot();\r\n    }\r\n\r\n    public void removeFiles(String[] files) throws Exception {\r\n        manager.removeFiles(files);\r\n    }\r\n\r\n    public void createDir(String name) throws Exception {\r\n        manager.createDir(name);\r\n    }\r\n\r\n    private void update() { // updates the current working directory\r\n        // clear the current known properties....\r\n        dirs.clear();\r\n        length.clear();\r\n        icons.clear();\r\n        modif.clear();\r\n        read.clear();\r\n        write.clear();\r\n        // list the current files\r\n        Vector<FileHandler> v = manager.getFileList();\r\n        if (v != null) {\r\n            for (FileHandler h : v) {\r\n                final String fn = h.getName();\r\n                if (h.getSize() < 0) { // folder\r\n                    dirs.add(fn);\r\n                    super.icons.put(fn, getFolderIcon());\r\n                } else { // file\r\n                    length.put(fn, h.getSize());\r\n                    super.icons.put(fn, getFileIcon(fn));\r\n                }\r\n                modif.put(fn, h.getModif());\r\n                read.put(fn, h.canRead());\r\n                write.put(fn, h.canWrite());\r\n            }\r\n        }\r\n    }\r\n\r\n    private Icon getFolderIcon() {\r\n        return folderIcon;\r\n    }\r\n\r\n    private Icon getUnknownIcon() {\r\n        if (unknownIcon != null) return unknownIcon;\r\n        try {\r\n            URL r = getClass().getResource(\"../icons/file.png\");\r\n            unknownIcon = new ImageIcon(r);\r\n        } catch (Exception e) {\r\n        }\r\n        return unknownIcon;\r\n    }\r\n\r\n    private final boolean okFS(String str) {\r\n        if (isWindows()) {\r\n            return !(str.contains(\"\\\\\") || str.contains(\"/\") || str.contains(\":\") || str.contains(\"*\") || str.contains(\"?\")\r\n                    || str.contains(\"\\\"\") || str.contains(\"<\") || str.contains(\">\") || str.contains(\"|\"));\r\n        }\r\n        return true;\r\n    }\r\n\r\n    private Icon getFileIcon(String fileName) {\r\n        // get the file extension, if any...\r\n        int index = fileName.lastIndexOf(\".\");\r\n        if (index < 0) { // no extension, use unknown file type...\r\n            return getUnknownIcon();\r\n        }\r\n        // else get the file extension...\r\n        String ext = fileName.substring(index + 1);\r\n        if (!okFS(ext))\r\n            return getUnknownIcon();\r\n        if (icons.containsKey(ext)) return icons.get(ext);\r\n        try {\r\n            //Create a temporary file with the specified extension\r\n            File file = File.createTempFile(\"icon\", \".\" + ext);\r\n            Icon icon = null;\r\n            if (file.exists()) {\r\n                try {\r\n                    icon = local.getSystemIcon(file);\r\n                    icons.put(ext, icon);\r\n                } catch (Throwable tt) {\r\n                }\r\n            }\r\n            //Delete the temporary file\r\n            file.delete();\r\n            if (icon != null)\r\n                return icon;\r\n            return getUnknownIcon();\r\n        } catch (Throwable t) {\r\n            t.printStackTrace();\r\n        }\r\n        return getUnknownIcon();\r\n    }\r\n\r\n    public String getWorkingDir() {\r\n        return manager.getWorkingDirectory();\r\n    }\r\n\r\n    public boolean canWrite() {\r\n        return manager.canWrite();\r\n    }\r\n\r\n    public String getOSName() {\r\n        return manager.getOSName();\r\n    }\r\n\r\n    public String getUserDir() {\r\n        return manager.getUserHome();\r\n    }\r\n\r\n    public boolean fileExists(String fileName) {\r\n        if (fileName == null) return false;\r\n        return modif.containsKey(fileName);\r\n    }\r\n\r\n    public String freeSpace() {\r\n        return manager.freeSpace();\r\n    }\r\n\r\n} // end of class RemoteSession\r\n\r\n\r\n"
  },
  {
    "path": "src/lia/util/net/copy/gui/session/Session.java",
    "content": "/*\r\n * $Id: Session.java 530 2009-06-04 13:38:13Z cipsm $\r\n */\r\npackage lia.util.net.copy.gui.session;\r\n\r\nimport javax.swing.*;\r\nimport java.util.HashMap;\r\nimport java.util.HashSet;\r\n\r\n/**\r\n * Helper class to handle the movements through current folders\r\n *\r\n * @author Ciprian Dobre\r\n */\r\npublic abstract class Session {\r\n\r\n    /**\r\n     * The working file attributes\r\n     */\r\n\r\n    public final HashSet<String> dirs = new HashSet<String>();\r\n\r\n    public final HashMap<String, Long> length = new HashMap<String, Long>();\r\n\r\n    public final HashMap<String, Icon> icons = new HashMap<String, Icon>();\r\n\r\n    public final HashMap<String, Long> modif = new HashMap<String, Long>();\r\n\r\n    public final HashMap<String, Boolean> read = new HashMap<String, Boolean>();\r\n\r\n    public final HashMap<String, Boolean> write = new HashMap<String, Boolean>();\r\n\r\n    public Session() {\r\n    }\r\n\r\n    /**\r\n     * Returns the current working directory for this FS session\r\n     */\r\n    public abstract String getWorkingDir();\r\n\r\n    /**\r\n     * Returns true if we can write in the directory denoted by the current working directory pathname\r\n     */\r\n    public abstract boolean canWrite();\r\n\r\n    /**\r\n     * Returns the name of the OS\r\n     */\r\n    public abstract String getOSName();\r\n\r\n    public abstract String getFileSeparator();\r\n\r\n    /**\r\n     * Returns the home directory of the user\r\n     */\r\n    public abstract String getUserDir();\r\n\r\n    /**\r\n     * Called when the user chooses from the drop-down list one of the root filesystems\r\n     */\r\n    public abstract void setAbsoluteDir(String dir) throws Exception;\r\n\r\n    /**\r\n     * Called when the user double clicks on a folder\r\n     */\r\n    public abstract void setRelativeDir(String dir) throws Exception;\r\n\r\n    /**\r\n     * Called when the user double clicks on the up folder\r\n     */\r\n    public abstract void setUpDir() throws Exception;\r\n\r\n    /**\r\n     * Returns the roots folders of the current FS - possible complete description\r\n     */\r\n    public abstract String[] getRoots() throws Exception;\r\n\r\n    public abstract String getShortRootName(String rootFolder);\r\n\r\n    /**\r\n     * Returns true if the currentDir is root\r\n     */\r\n    public abstract boolean isRoot();\r\n\r\n    /**\r\n     * Check whether the file denoted by fileName exists or not\r\n     */\r\n    public abstract boolean fileExists(String fileName);\r\n\r\n    /**\r\n     * Removes the files denoted\r\n     */\r\n    public abstract void removeFiles(String[] files) throws Exception;\r\n\r\n    /**\r\n     * Creates a new directory\r\n     */\r\n    public abstract void createDir(String dirName) throws Exception;\r\n\r\n    public abstract String freeSpace();\r\n\r\n} // end of class Session\r\n\r\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/ApMonReportingTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport apmon.ApMon;\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.FDTWriterSession;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Vector;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Simple implementation for a {@link FDTReportingTask} which is used to send data\n * through <code>ApMon</code>\n *\n * @author ramiro\n */\npublic class ApMonReportingTask extends FDTReportingTask {\n\n    private static final Logger logger = Logger.getLogger(\"lia.util.net.copy.monitoring.ApMonReportingTask\");\n\n    private static final ApMon apMon;\n\n    static {\n        ApMon apMonInstace = null;\n        try {\n            System.out.println(\"Starting ApMonReportingTask ...\");\n            apMonInstace = Utils.getApMon();\n            System.out.println(\"ApMonReportingTask started!\");\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception getting apmon instance\", t);\n        }\n\n        apMon = apMonInstace;\n    }\n\n    private static final void sendParams(final HashMap<String, HashMap<String, Double>> paramsToSend, final String clusterName) throws Exception {\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, \" Sending to ApMonReportingTask :- ClusterName: \" + clusterName + \" Params: \" + paramsToSend);\n        }\n\n        if (paramsToSend.size() > 0) {\n\n            for (Map.Entry<String, HashMap<String, Double>> entry : paramsToSend.entrySet()) {\n                HashMap<String, Double> hToSend = entry.getValue();\n                Vector<Double> paramValues = null;\n                Vector<String> paramNames = null;\n                Vector<Integer> paramTypes = null;\n                if (hToSend.size() > 0) {\n                    paramValues = new Vector<Double>(hToSend.size());\n                    paramNames = new Vector<String>(hToSend.size());\n                    paramTypes = new Vector<Integer>(hToSend.size());\n\n                    for (Map.Entry<String, Double> pEntry : hToSend.entrySet()) {\n                        paramValues.add(pEntry.getValue());\n                        paramNames.add(pEntry.getKey());\n                        paramTypes.add(ApMon.XDR_REAL64);\n                    }\n                }\n\n                if (paramValues != null) {\n                    apMon.sendParameters(clusterName, entry.getKey(), paramValues.size(), paramNames, paramTypes, paramValues);\n                }\n            }\n        }\n    }\n\n    private void publisStartFinishParams(final FDTSession fdtSession) {\n        if (fdtSession != null) {\n            try {\n                final HashMap<String, HashMap<String, Double>> paramsToSend = new HashMap<String, HashMap<String, Double>>();\n                final HashMap<String, Double> fdtSessionParams = new HashMap<String, Double>();\n                final FDTSessionMonitoringTask fdtSessionMTask = fdtSession.getMonitoringTask();\n                String apMonClusterName = \"N/A\";\n\n                if (fdtSessionMTask != null) {\n                    if (fdtSession instanceof FDTWriterSession) {\n                        final double rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"DISK_WRITE_MB\", rate);\n                        final double tSize = fdtSession.getSize() / (double) Utils.MEGA_BYTE;\n                        final double cSize = fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"TotalMBytes\", tSize);\n                        fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                        fdtSessionParams.put(\"Status\", (double) fdtSession.getCurrentStatus());\n\n                        if (fdtSession.getSize() != 0) {\n                            fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                        }\n\n                        final String monID = fdtSession.getMonID();\n                        if (monID != null) {\n                            paramsToSend.put(monID, fdtSessionParams);\n                        } else {\n                            paramsToSend.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n                        }\n                        apMonClusterName = \"Readers\";\n\n                    } else if (fdtSession instanceof FDTReaderSession) {\n                        final double rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"DISK_READ_MB\", rate);\n                        final double tSize = fdtSession.getSize() / (double) Utils.MEGA_BYTE;\n                        final double cSize = fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"TotalMBytes\", tSize);\n                        fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                        if (fdtSession.getSize() != 0) {\n                            fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                        }\n                        fdtSessionParams.put(\"Status\", (double) fdtSession.getCurrentStatus());\n\n                        final String monID = fdtSession.getMonID();\n                        if (monID != null) {\n                            paramsToSend.put(monID, fdtSessionParams);\n                        } else {\n                            paramsToSend.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n                        }\n\n                        apMonClusterName = \"Writers\";\n\n                    } else {\n                        logger.log(Level.WARNING, \"[ERROR] FDT Session is not an \\\"instanceof\\\" FDTWriterSession or FDTReaderSession!!!\");\n                        return;\n                    }\n\n                    if (paramsToSend.size() > 0) {\n\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \" Sending to ApMonReportingTask :- \" + apMonClusterName + \" Params: \" + paramsToSend);\n                        }\n                        for (Map.Entry<String, HashMap<String, Double>> entry : paramsToSend.entrySet()) {\n                            HashMap<String, Double> hToSend = entry.getValue();\n                            Vector<Double> paramValues = null;\n                            Vector<String> paramNames = null;\n                            Vector<Integer> paramTypes = null;\n                            if (hToSend.size() > 0) {\n                                paramValues = new Vector<Double>(hToSend.size());\n                                paramNames = new Vector<String>(hToSend.size());\n                                paramTypes = new Vector<Integer>(hToSend.size());\n\n                                for (Map.Entry<String, Double> pEntry : hToSend.entrySet()) {\n                                    paramValues.add(pEntry.getValue());\n                                    paramNames.add(pEntry.getKey());\n                                    paramTypes.add(ApMon.XDR_REAL64);\n                                }\n                            }\n\n                            if (paramValues != null) {\n                                apMon.sendParameters(apMonClusterName, entry.getKey(), paramValues.size(), paramNames, paramTypes, paramValues);\n                            }\n                        }\n                    }\n\n                } else {\n                    logger.log(Level.WARNING, \"[ERROR] FDTSessionMonitoringTask is null in finishFDTSession(fdtSession)!!!\");\n                }\n\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got expcetion notifying last params for \" + fdtSession.sessionID(), t);\n            }\n        } else {\n            logger.log(Level.WARNING, \"[ERROR] FDT Session is null in finishFDTSession(fdtSession)!!!\");\n        }\n    }\n\n    public void startFDTSession(final FDTSession fdtSession) {\n        publisStartFinishParams(fdtSession);\n    }\n\n    public void finishFDTSession(final FDTSession fdtSession) {\n        publisStartFinishParams(fdtSession);\n    }\n\n    public void run() {\n        try {\n\n            if (logger.isLoggable(Level.FINEST)) {\n                logger.log(Level.FINEST, \"ApMonReportingTask entering run()\");\n            }\n\n            HashMap<String, HashMap<String, Double>> paramsToSend = getReaderParams();\n\n            if (paramsToSend.size() > 0) {\n                sendParams(paramsToSend, \"Readers\");\n            }\n\n            paramsToSend = getWriterParams();\n\n            double totalNet = 0;\n            double totalDisk = 0;\n\n            if (paramsToSend.size() > 0) {\n\n                for (Map.Entry<String, HashMap<String, Double>> entry : paramsToSend.entrySet()) {\n                    HashMap<String, Double> hToSend = entry.getValue();\n                    if (hToSend.size() > 0) {\n                        Double dToAdd = hToSend.get(\"NET_IN_Mb\");\n                        if (dToAdd != null) {\n                            totalNet += dToAdd;\n                        }\n\n                        dToAdd = hToSend.get(\"DISK_WRITE_MB\");\n                        if (dToAdd != null) {\n                            totalDisk += dToAdd;\n                        }\n                    }\n                }\n            }\n\n            if (paramsToSend.size() > 0) {\n                sendParams(paramsToSend, \"Writers\");\n            }\n\n            if (Config.getInstance().getHostName() == null) {\n                HashMap<String, Double> localParams = new HashMap<String, Double>();\n                localParams.put(\"CLIENTS_NO\", (double) paramsToSend.size());\n                localParams.put(\"DISK_WRITE_MB\", totalDisk);\n                localParams.put(\"NET_IN_Mb\", totalNet);\n\n//                lisaMon.sendServerParameters(\"FDT_PARAMS\", localParams);\n            }\n\n//            HashMap<String, Double> fdtLisaParams = FDTInternalMonitoringTask.getInstance().getLisaParams();            \n//            \n//            String key = \"FDT_MON:\";\n//            if(Config.getInstance().getHostName() == null) {\n//                key += Config.getInstance().getPort();\n//            } else {\n//                String rPort = \"\";\n//                it = diskReaderManager.getSessions().iterator();\n//                while(it.hasNext()) {\n//                    fdtSession = it.next();\n//                    rPort += fdtSession.getLocalPort();\n//                }\n//\n//                it = diskWriterManager.getSessions().iterator();\n//                while(it.hasNext()) {\n//                    fdtSession = it.next();\n//                    rPort += fdtSession.getLocalPort();\n//                }\n//                \n//                if(rPort.length() == 0) {\n//                    rPort = \"UNK\";\n//                }\n//                \n//                key += rPort;\n//            }\n//\n//            if(logger.isLoggable(Level.FINER)) {\n//                logger.log(Level.FINER, \"FDT Params: \" + fdtLisaParams + \" Key: \" + key);\n//            }\n//            \n//            lisaMon.sendServerParameters(key, fdtLisaParams);\n\n        } catch (Throwable t) {\n            logger.log(Level.INFO, \" LISAReportingTask got exception:\", t);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/ClientTransportMonitorTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.copy.monitoring.lisa.LISAReportingTask;\n\nimport java.util.HashMap;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is used to monitor the Client transfer and to notify LISA\n * if something goes wrong\n *\n * @author ramiro\n */\npublic class ClientTransportMonitorTask implements Runnable {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(ClientTransportMonitorTask.class.getName());\n\n    private static final double THRESHOLD = 0.01;\n    private static final int FAILED_ITERATIONS_THRESHOLD = 3;\n    private static final LISAReportingTask lisaReportingTask = LISAReportingTask.getInstance();\n    private final DiskReaderManagerMonitoringTask diskReaderMonitoringTask;\n    double cRate = Double.MAX_VALUE;\n    private boolean isTransportDown;\n\n    private int failedIterations;\n\n\n    public ClientTransportMonitorTask(DiskReaderManagerMonitoringTask diskReaderMonitoringTask) {\n        logger.log(Level.INFO, \"ClientTransportMonitorTask started! \");\n        this.diskReaderMonitoringTask = diskReaderMonitoringTask;\n        failedIterations = 0;\n        isTransportDown = false;\n    }\n\n    private void notifyTransportDown() {\n        logger.log(Level.WARNING, \"\\n\\n [ ClientTransportMonitorTask ] Current Rate \" + cRate + \" & failedIterations: \" + failedIterations + \" notifying LISA Wrapper \\n\\n\");\n        isTransportDown = true;\n        try {\n            lisaReportingTask.sendClientNow(\"RESTARTME\", new HashMap<String, Double>());\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"\\n\\n [ ClientTransportMonitorTask ]  failed to notify LISA !! \\n\\n\", t);\n        }\n    }\n\n    public boolean isTransportDown() {\n        return isTransportDown;\n    }\n\n    public void run() {\n        cRate = diskReaderMonitoringTask.getTotalRate();\n        if (diskReaderMonitoringTask.getTotalRate() < THRESHOLD) {\n            failedIterations++;\n        } else {\n            failedIterations = 0;\n        }\n\n        if (failedIterations > FAILED_ITERATIONS_THRESHOLD) {\n            notifyTransportDown();\n        } else {\n            isTransportDown = false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/ConsoleReportingTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.disk.DiskReaderManager;\nimport lia.util.net.copy.disk.DiskWriterManager;\nimport lia.util.net.copy.monitoring.base.AbstractAccountableMonitoringTask;\nimport lia.util.net.copy.transport.TCPTransportProvider;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is the only class which should report to the stdout\n *\n * @author ramiro\n */\npublic class ConsoleReportingTask extends AbstractAccountableMonitoringTask {\n\n    private static final Logger logger = Logger.getLogger(ConsoleReportingTask.class.getName());\n\n    private static final DiskWriterManager diskWriterManager = DiskWriterManager.getInstance();\n\n    private static final DiskReaderManager diskReaderManager = DiskReaderManager.getInstance();\n    private static final ConsoleReportingTask thisInstace = new ConsoleReportingTask();\n    // private final DateFormat dateFormat = new SimpleDateFormat(\"dd/MM/yy HH:mm:ss\");\n    private final DateFormat dateFormat = new SimpleDateFormat(\"dd/MM HH:mm:ss\");\n    private final Set<FDTSession> oldReaderSessions = new TreeSet<FDTSession>();\n    private final Set<FDTSession> oldWriterSessions = new TreeSet<FDTSession>();\n    private final boolean customLog;\n\n    private ConsoleReportingTask() {\n        super(null);\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"\\n\\n  [ ConsoleReportingTask ] initiated !!!! \\n\\n\");\n        }\n        customLog = Utils.isCustomLog();\n    }\n\n    public static final ConsoleReportingTask getInstance() {\n        return thisInstace;\n    }\n\n    private final boolean reportStatus(final Set<FDTSession> currentSessionSet, final Set<FDTSession> oldSessionSet,\n                                       final String tag, final StringBuilder sb) {\n        boolean shouldReport = false;\n\n        if (oldSessionSet.size() > 0) {\n            double totalReadRate = 0;\n            boolean reportMultipleSessions = false;\n\n            if (oldSessionSet.size() > 1) {\n                reportMultipleSessions = true;\n                sb.append(oldSessionSet.size()).append(\" active sessions:\");\n            }\n\n            for (Iterator<FDTSession> it = oldSessionSet.iterator(); it.hasNext(); ) {\n                final FDTSession fdtSession = it.next();\n                final TCPTransportProvider tcpTransportProvider = fdtSession.getTransportProvider();\n\n                if (!currentSessionSet.contains(fdtSession)) {\n                    if (tcpTransportProvider == null) {\n                        // this is real big .... BUG?????\n                        logger.log(Level.WARNING,\n                                \" [ ConsoleReportingTask ] The session: \" + fdtSession\n                                        .sessionID() + \" is no longer \"\n                                        + \"available, but canot remove trasport provider from monitoring queue. It's probably a BUG in FDT\");\n                        continue;\n                    }\n                    if (logger.isLoggable(Level.FINE)) {\n                        logger.log(Level.FINE, \" [ ConsoleReportingTask ]  Removing tcpTransportProvider \"\n                                + tcpTransportProvider + \" for session: \" + fdtSession.sessionID());\n                    }\n                    remove(tcpTransportProvider);\n                    it.remove();\n                    continue;\n                }\n\n                if (tcpTransportProvider != null) {\n                    if (getMonCount(tcpTransportProvider) == 0)\n                        continue;\n\n                    final double totalRate = getTotalRate(tcpTransportProvider);\n                    final double avgTotalRate = getAvgTotalRate(tcpTransportProvider);\n\n                    shouldReport = true;\n                    totalReadRate += totalRate;\n\n                    if (reportMultipleSessions) {\n                        sb.append(\"\\n\").append(fdtSession.sessionID());\n                    }\n                    sb.append(tag).append(Utils.formatWithBitFactor(8 * totalRate, 0, \"/s\")).append(\"\\tAvg: \")\n                            .append(Utils.formatWithBitFactor(8 * avgTotalRate, 0, \"/s\"));\n\n                    final long dtMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - fdtSession.startTimeNanos);\n                    if (fdtSession.getSize() > 0 && dtMillis > 20 * 1000) {\n                        final long tcpSize = tcpTransportProvider.getUtilBytes();\n                        final double cSize = (tcpSize <= 0L) ? 0D : tcpSize;\n                        if (cSize > 0) {\n                            final double tSize = (fdtSession.getSize() <= 0L) ? 0D : fdtSession.getSize();\n                            sb.append(\" \").append(Utils.percentDecimalFormat((cSize * 100) / tSize)).append(\"%\");\n                            final double remainingSeconds = (fdtSession.getSize() - cSize) / avgTotalRate;\n                            sb.append(\" ( \").append(Utils.getETA((long) remainingSeconds)).append(\" )\");\n                        }\n                    }\n                }\n            } // for all old sessions\n\n            if (reportMultipleSessions) {\n                // get it in bits/s from bytes/s\n                totalReadRate *= 8;\n                sb.append(\"\\nTotal \").append(tag).append(Utils.formatWithBitFactor(totalReadRate, 0, \"/s\"));\n            }\n        }\n\n        // add all new sessions\n        for (final FDTSession fdtSession : currentSessionSet) {\n            if (!oldSessionSet.contains(fdtSession)) {\n                final TCPTransportProvider tcpTransportProvider = fdtSession.getTransportProvider();\n                if (tcpTransportProvider != null) {\n                    if (addIfAbsent(tcpTransportProvider, logger.isLoggable(Level.FINER) ? true : false)) {\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \" [ ConsoleReportingTask ]  Adding tcpTransportProvider \"\n                                    + tcpTransportProvider + \" for session: \" + fdtSession.sessionID());\n                        }\n                    } else {\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \" [ ConsoleReportingTask ]  Unable to add tcpTransportProvider \"\n                                    + tcpTransportProvider + \" for session: \" + fdtSession.sessionID());\n                        }\n                    }\n\n                    oldSessionSet.add(fdtSession);\n                }\n            }\n        }\n\n        return shouldReport;\n    }\n\n    private void reportStatus() {\n        StringBuilder sb = new StringBuilder(8192);\n\n        boolean shouldReport = (reportStatus(diskWriterManager.getSessions(), oldWriterSessions, \"Net In: \", sb)\n                || reportStatus(diskReaderManager.getSessions(), oldReaderSessions, \"Net Out: \", sb));\n\n        if (shouldReport) {\n            logger.info(sb.toString());\n        }\n\n    }\n\n    @Override\n    public void rateComputed() {\n        try {\n            reportStatus();\n        } catch (Throwable t1) {\n            logger.log(Level.WARNING, \" [ ConsoleReportingTask ] Got exception while reporting\", t1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/DiskReaderManagerMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.Accountable;\nimport lia.util.net.copy.disk.DiskReaderManager;\nimport lia.util.net.copy.monitoring.base.AbstractAccountableMonitoringTask;\n\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * Monitors disk activity\n *\n * @author ramiro\n */\npublic class DiskReaderManagerMonitoringTask extends AbstractAccountableMonitoringTask {\n\n    private static AtomicBoolean inited = new AtomicBoolean(false);\n    Config config = Config.getInstance();\n\n    public DiskReaderManagerMonitoringTask(DiskReaderManager drm) {\n        super(new Accountable[]{drm});\n    }\n\n    public void rateComputed() {\n\n        if (inited.compareAndSet(false, true) && config.getHostName() != null && config.isLisaRestartEnabled() && !config.isLisaDisabled()) {\n            //is Client lisa is enabled and restart also... start monitoring transfer\n            Utils.getMonitoringExecService().scheduleWithFixedDelay(new ClientTransportMonitorTask(this), 6, 6, TimeUnit.SECONDS);\n        }\n\n        if (DiskReaderManager.getInstance().sessionsSize() == 0) {\n            resetAllCounters();\n        }\n    }\n\n    public double getTotalRate() {\n        return getTotalRate(DiskReaderManager.getInstance());\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/DiskWriterManagerMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.copy.Accountable;\nimport lia.util.net.copy.disk.DiskWriterManager;\nimport lia.util.net.copy.monitoring.base.AbstractAccountableMonitoringTask;\n\n/**\n * Monitors disk activity\n *\n * @author ramiro\n */\npublic class DiskWriterManagerMonitoringTask extends AbstractAccountableMonitoringTask {\n\n\n    private final DiskWriterManager diskWriterManager;\n\n\n    public DiskWriterManagerMonitoringTask(DiskWriterManager diskWriterManager) {\n        super(new Accountable[]{diskWriterManager});\n        this.diskWriterManager = diskWriterManager;\n    }\n\n    public void rateComputed() {\n        if (diskWriterManager.sessionsSize() == 0) {\n            resetAllCounters();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/DiskWriterMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport apmon.ApMon;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.disk.DiskWriterTask;\n\nimport java.util.Date;\nimport java.util.Vector;\nimport java.util.concurrent.locks.Lock;\nimport java.util.logging.Logger;\n\n/**\n * Monitors disk activity per writer\n *\n * @author ramiro\n */\npublic class DiskWriterMonitoringTask implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(DiskWriterManagerMonitoringTask.class.getName());\n\n    private final Lock countersRLock;\n\n    long lastDtTake;\n    long lastDtWrite;\n    long lastDtFinishSession;\n    long lastDtTotal;\n\n    boolean initialized = false;\n    StringBuilder sb = new StringBuilder();\n\n    DiskWriterTask writerTask;\n    Vector<String> paramNames = new Vector<String>();\n    Vector<Double> paramValues = new Vector<Double>();\n    Vector<Integer> valueTypes = new Vector<Integer>();\n\n    public DiskWriterMonitoringTask(DiskWriterTask writerTask) {\n        this.writerTask = writerTask;\n        countersRLock = writerTask.getCountersRLock();\n    }\n\n    String getNiceProcent(double value) {\n\n        int aux = (int) (value * 100.0);\n        if (value >= 1) {\n\n            if ((aux % 100) != 0)\n                return aux / 100f + \"%\";\n\n            return (int) value + \"%\";\n        } else if (value < 1 && value > 0) {\n            return aux / 100f + \"%\";\n        }\n\n        return value + \"%\";\n    }\n\n    public void run() {\n\n        sb.setLength(0);\n        sb.append(\"\\n[ FileWriterMonitorTask Status @ \").append(new Date().toString()).append(\" ]\\n\");\n        sb.append(\"\\n******************************************************\\n\");\n\n        long diffDtTotal = 0, diffDtWrite = 0, diffDtFinishSession = 0, diffDtTake = 0, diffDtOther = 0;\n        double procWrite = 0, procFinish = 0, procTake = 0, procOther = 0;\n\n        boolean reportOk = false;\n\n        countersRLock.lock();\n        try {\n            if (this.lastDtTotal != writerTask.dtTotal) {\n                reportOk = true;\n                if (initialized) {\n                    diffDtTotal = writerTask.dtTotal - this.lastDtTotal;\n                    diffDtTake = writerTask.dtTake - this.lastDtTake;\n                    diffDtFinishSession = writerTask.dtFinishSession - this.lastDtFinishSession;\n                    diffDtWrite = writerTask.dtWrite - this.lastDtWrite;\n                    diffDtOther = diffDtTotal - (diffDtTake + diffDtFinishSession + diffDtWrite);\n\n                }\n                lastDtTake = writerTask.dtTake;\n                lastDtTotal = writerTask.dtTotal;\n                lastDtWrite = writerTask.dtWrite;\n                lastDtFinishSession = writerTask.dtFinishSession;\n            }\n        } finally {\n            countersRLock.unlock();\n        }\n\n        if (!initialized) {\n            initialized = true;\n            initParams();\n            return;\n        }\n\n        sb.append(\"PoolStats:\");\n//        sb.append(\"\\nPayload Pool: [ \").append(bufferPool.getSize()).append(\" / \").append(bufferPool.getCapacity()).append(\" ]\");\n//        sb.append(\"\\nPacket Header Pool: [ \").append(Utils.getHeaderBufferPool().getSize()).append(\" / \").append(Utils.getHeaderBufferPool().getCapacity()).append(\" ]\");\n        if (reportOk) {\n\n            procWrite = (diffDtWrite * 100D) / diffDtTotal;\n            procFinish = (diffDtFinishSession * 100D) / diffDtTotal;\n            procTake = (diffDtTake * 100D) / diffDtTotal;\n            procOther = 100 - (procWrite + procFinish + procTake);\n\n            sb.append(\"\\n DT = \").append(diffDtTotal);\n            sb.append(\" DtTake = \").append(diffDtTake).append(\" ( \").append(getNiceProcent(procTake)).append(\" ) \");\n            sb.append(\" DtWrite = \").append(diffDtWrite).append(\" ( \").append(getNiceProcent(procWrite)).append(\" )\");\n            sb.append(\" DtFinish = \").append(diffDtFinishSession).append(\" ( \").append(getNiceProcent(procFinish)).append(\" )\");\n            sb.append(\" DtOther = \").append(diffDtOther).append(\" ( \").append(getNiceProcent(procOther)).append(\" )\");\n        }\n\n        sb.append(\"\\n******************************************************\\n\");\n\n        System.out.println(sb.toString());\n        //use the apmon monitoring\n        if (Utils.getApMon() != null) {\n            try {\n//                Utils.getApMon().sendParameter( null, null, \"PoolStat_Available\", bufferPool.getSize());\n//                Utils.getApMon().sendParameter( null, null, \"PoolStat_Total\", bufferPool.getCapacity());\n                if (reportOk) {\n                    paramValues.set(0, new Double(procTake));\n                    paramValues.set(1, new Double(procWrite));\n                    paramValues.set(2, new Double(procFinish));\n                    paramValues.set(3, new Double(procOther));\n                    Utils.getApMon().sendParameters(null, null, paramNames.size(), paramNames, valueTypes, paramValues);\n                }\n            } catch (Exception ex) {\n                logger.warning(\"Could not send monitoring information to MonALISA.\");\n                ex.printStackTrace();\n            }\n        }\n    }//run()\n\n    public void initParams() {\n        String[] names = {\"Network_GET\", \"Disk_PUT\", \"File_CLOSE\", \"Other\"};\n        for (int i = 0; i < names.length; i++) {\n            paramNames.add(names[i]);\n            paramValues.add(null);\n            valueTypes.add(ApMon.XDR_REAL64);\n        }\n        ;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/FDTInternalMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.HeaderBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.disk.DiskReaderManager;\nimport lia.util.net.copy.disk.DiskWriterManager;\nimport lia.util.net.copy.disk.DiskWriterTask;\n\nimport java.util.*;\nimport java.util.concurrent.locks.Lock;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Used for internal monitoring\n * It will log if the logging level if -printStats is enabled\n *\n * @author ramiro\n */\npublic class FDTInternalMonitoringTask implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(FDTInternalMonitoringTask.class.getName());\n    private static final DiskWriterManager diskWriterManager = DiskWriterManager.getInstance();\n    private static final DiskReaderManager diskReaderManager = DiskReaderManager.getInstance();\n    private static final FDTInternalMonitoringTask _theInstance;\n    private static final Config config = Config.getInstance();\n    private static final Level STATS_LEVEL = config.getStatsLevel();\n    private static final String EOL = System.getProperty(\"line.separator\", \"\\n\");\n    private static boolean initialized = false;\n\n    static {\n        synchronized (FDTInternalMonitoringTask.class) {\n            _theInstance = new FDTInternalMonitoringTask();\n            initialized = true;\n            FDTInternalMonitoringTask.class.notifyAll();\n        }\n    }\n\n    //Params to monitor\n    int dbpool_total;\n    int dbpool_free;\n    int hpool_total;\n    int hpool_free;\n    int mon_queue_count;\n    int fdt_wdisk_ses_count;\n    int fdt_rdisk_ses_count;\n    //It's used from a single thread\n    StringBuilder sb = null;\n    HashMap<Integer, HashMap<Integer, WriterAccountingContors>> hmWriters;\n\n    //only one instance per application\n    private FDTInternalMonitoringTask() {\n        sb = new StringBuilder(2048);\n        hmWriters = new HashMap<Integer, HashMap<Integer, WriterAccountingContors>>();\n    }\n\n    private static final String getNiceProcent(double value) {\n\n        int aux = (int) (value * 100.0);\n        if (value >= 1) {\n\n            if ((aux % 100) != 0) return aux / 100f + \"%\";\n\n            return (int) value + \"%\";\n        } else if (value < 1 && value > 0) {\n            return aux / 100f + \"%\";\n        }\n\n        return value + \"%\";\n    }\n\n    public static final FDTInternalMonitoringTask getInstance() {\n        if (!initialized) {\n            synchronized (FDTInternalMonitoringTask.class) {\n                while (!initialized) {\n                    try {\n                        FDTInternalMonitoringTask.class.wait();\n                    } catch (Throwable t) {\n                        t.printStackTrace();\n                    }\n                }\n            }//end sync\n        }\n        return _theInstance;\n    }\n\n    private final void printStats() {\n        sb.setLength(0);\n\n        sb.append(EOL).append(EOL).append(\" *** FDT Stats @ \").append(new Date()).append(\" *** \").append(EOL).append(EOL);\n        sb.append(\" BuffPool [ \").append(dbpool_free).append(\" / \").append(dbpool_total);\n        sb.append(\" ] HeaderBPool [ \").append(hpool_free).append(\" / \").append(hpool_total).append(\" ]\").append(EOL);\n        sb.append(EOL).append(EOL).append(\" BuffPool Identity map stats\").append(DirectByteBufferPool.getInstance().identityMapStats()).append(EOL);\n        sb.append(EOL).append(EOL).append(\" HeaderPool Identity map stats\").append(HeaderBufferPool.getInstance().identityMapStats()).append(EOL);\n        sb.append(\" MonitoringQueue \").append(mon_queue_count).append(EOL);\n        Map<Integer, List<DiskWriterTask>> writersMap = diskWriterManager.getWritersMap();\n        sb.append(\" PartitionIDs: \").append(writersMap.size());\n        for (final Map.Entry<Integer, List<DiskWriterTask>> entry : writersMap.entrySet()) {\n            final Integer partitionID = entry.getKey();\n            sb.append(\" [ partitionID: \").append(partitionID).append(\" workers: \").append(writersMap.get(entry.getValue().size())).append(\" qSize: \").append(diskWriterManager.getQueueSize(partitionID.intValue())).append(\" ] \");\n        }\n        sb.append(EOL);\n        sb.append(\" Disk Writer Sessions: \").append(fdt_wdisk_ses_count).append(\" Disk Reader Sessions: \").append(fdt_rdisk_ses_count);\n        sb.append(EOL);\n\n        for (Iterator<Map.Entry<Integer, HashMap<Integer, WriterAccountingContors>>> it = hmWriters.entrySet().iterator(); it.hasNext(); ) {\n            Map.Entry<Integer, HashMap<Integer, WriterAccountingContors>> entry = it.next();\n\n            Integer id = entry.getKey();\n            HashMap<Integer, WriterAccountingContors> iVal = entry.getValue();\n\n            for (Map.Entry<Integer, WriterAccountingContors> iEntry : iVal.entrySet()) {\n\n                Integer writerID = iEntry.getKey();\n                WriterAccountingContors wac = iEntry.getValue();\n\n                if (wac.reportOk) {\n                    sb.append(EOL).append(\" DiskWriterStat [ PartitionID: \" + id + \" writerID \" + writerID + \" ] WOnQueue \").append(getNiceProcent(wac.procTake));\n                    sb.append(\" WaitOnWrite \").append(getNiceProcent(wac.procWrite));\n                    sb.append(\" WaitOnFinish \").append(getNiceProcent(wac.procFinish));\n                    sb.append(\" WaitOnOther \").append(getNiceProcent(wac.procOther));\n                }\n            }\n\n            sb.append(EOL);\n        }\n\n        sb.append(EOL).append(EOL).append(\" *** ==== ***\").append(EOL);\n        logger.log(STATS_LEVEL, sb.toString());\n    }\n\n    private void updateWritersAccounting() {\n        Map<Integer, List<DiskWriterTask>> currentWriters = diskWriterManager.getWritersMap();\n\n        for (Map.Entry<Integer, List<DiskWriterTask>> entry : currentWriters.entrySet()) {\n            Integer id = entry.getKey();\n            List<DiskWriterTask> partitionWritersList = entry.getValue();\n\n            for (DiskWriterTask writerTask : partitionWritersList) {\n                long diffDtTotal = 0, diffDtWrite = 0, diffDtFinishSession = 0, diffDtTake = 0, diffDtOther = 0;\n                boolean init = false;\n\n                HashMap<Integer, WriterAccountingContors> wacMap = hmWriters.get(id);\n\n                if (wacMap == null) {\n                    wacMap = new HashMap<Integer, WriterAccountingContors>();\n                    hmWriters.put(id, wacMap);\n                }\n\n                WriterAccountingContors wac = wacMap.get(Integer.valueOf(writerTask.writerID()));\n\n                if (wac == null) {\n                    wac = new WriterAccountingContors(writerTask.getCountersRLock());\n                    wacMap.put(Integer.valueOf(writerTask.writerID()), wac);\n                    init = true;\n                }\n\n                wac.reportOk = false;\n\n                wac.countersRLock.lock();\n                try {\n                    if (wac.lastDtTotal != writerTask.dtTotal) {\n                        wac.reportOk = true;\n\n                        if (!init) {\n                            diffDtTotal = writerTask.dtTotal - wac.lastDtTotal;\n                            diffDtTake = writerTask.dtTake - wac.lastDtTake;\n                            diffDtFinishSession = writerTask.dtFinishSession - wac.lastDtFinishSession;\n                            diffDtWrite = writerTask.dtWrite - wac.lastDtWrite;\n                            diffDtOther = diffDtTotal - (diffDtTake + diffDtFinishSession + diffDtWrite);\n\n                        }\n\n                        wac.lastDtTake = writerTask.dtTake;\n                        wac.lastDtTotal = writerTask.dtTotal;\n                        wac.lastDtWrite = writerTask.dtWrite;\n                        wac.lastDtFinishSession = writerTask.dtFinishSession;\n                    } else {\n                        if (logger.isLoggable(Level.FINER)) {\n                            logger.log(Level.FINER, \" The writer seem idle same time [ \" + wac.lastDtTotal + \" ] as in previous iteration \");\n                        }\n                    }\n                } finally {\n                    wac.countersRLock.unlock();\n                }\n\n                //Just for protection - if the writer was restarted by the manager\n                if (diffDtTotal < 0 || diffDtTake < 0 || diffDtFinishSession < 0 || diffDtWrite < 0) {\n                    if (logger.isLoggable(Level.FINER)) {\n                        logger.log(Level.FINER, new StringBuilder(\" Report NOK smth is decreasing \").append(\" diffDtTotal = \").append(diffDtTotal).append(\" diffDtTake = \").append(diffDtTake).append(\" diffDtFinishSession = \").append(diffDtFinishSession).append(\" diffDtWrite = \").append(diffDtWrite).append(\" diffDtOther = \").append(diffDtOther).toString());\n                    }\n                    wac.reportOk = false;\n                }\n\n                if (init) {\n                    continue;\n                }\n\n                if (wac.reportOk) {\n\n                    wac.procWrite = (diffDtWrite * 100D) / diffDtTotal;\n                    wac.procFinish = (diffDtFinishSession * 100D) / diffDtTotal;\n                    wac.procTake = (diffDtTake * 100D) / diffDtTotal;\n                    wac.procOther = 100 - (wac.procWrite + wac.procFinish + wac.procTake);\n\n                }\n            }\n        }//end for\n\n        //check for dead writers\n        for (Iterator<Integer> it = hmWriters.keySet().iterator(); it.hasNext(); ) {\n            Integer partitionID = it.next();\n            if (!currentWriters.containsKey(partitionID)) {\n                it.remove();\n            }\n        }\n    }\n\n    public HashMap<String, Double> getLisaParams() {\n        HashMap<String, Double> fdtLisaParams = new HashMap<String, Double>();\n\n        fdtLisaParams.put(\"dbpool_total\", (double) dbpool_total);\n        fdtLisaParams.put(\"dbpool_free\", (double) dbpool_free);\n\n        fdtLisaParams.put(\"hpool_total\", (double) hpool_total);\n        fdtLisaParams.put(\"hpool_free\", (double) hpool_free);\n        fdtLisaParams.put(\"mon_queue\", (double) mon_queue_count);\n\n        fdtLisaParams.put(\"fdt_ses_wdisk\", (double) fdt_wdisk_ses_count);\n        fdtLisaParams.put(\"fdt_ses_rdisk\", (double) fdt_rdisk_ses_count);\n\n        //Writers accounting\n        for (Iterator<Map.Entry<Integer, HashMap<Integer, WriterAccountingContors>>> it = hmWriters.entrySet().iterator(); it.hasNext(); ) {\n            Map.Entry<Integer, HashMap<Integer, WriterAccountingContors>> entry = it.next();\n\n            Integer pid = entry.getKey();\n            HashMap<Integer, WriterAccountingContors> wacMap = entry.getValue();\n\n            for (Iterator<Map.Entry<Integer, WriterAccountingContors>> iti = wacMap.entrySet().iterator(); iti.hasNext(); ) {\n                Map.Entry<Integer, WriterAccountingContors> ientry = iti.next();\n\n                Integer wID = ientry.getKey();\n                WriterAccountingContors wac = ientry.getValue();\n\n                if (wac.reportOk) {\n\n                    final String wPrefix = \"pID_\" + pid + \"_wID_\" + wID + \"_\";\n\n                    fdtLisaParams.put(wPrefix + \"w_take\", wac.procTake);\n                    fdtLisaParams.put(wPrefix + \"w_write\", wac.procWrite);\n                    fdtLisaParams.put(wPrefix + \"w_finish\", wac.procFinish);\n                    fdtLisaParams.put(wPrefix + \"w_other\", wac.procOther);\n                }\n            }\n\n        }\n\n        return fdtLisaParams;\n    }\n\n    public void run() {\n\n        try {\n\n            final long sTime = System.nanoTime();\n\n            dbpool_total = DirectByteBufferPool.getInstance().getCapacity();\n            dbpool_free = DirectByteBufferPool.getInstance().getSize();\n\n            hpool_total = HeaderBufferPool.getInstance().getCapacity();\n            hpool_free = HeaderBufferPool.getInstance().getSize();\n\n            mon_queue_count = Utils.getMonitoringExecService().getQueue().size();\n\n            fdt_wdisk_ses_count = diskWriterManager.getSessions().size();\n            fdt_rdisk_ses_count = diskReaderManager.getSessions().size();\n\n            updateWritersAccounting();\n\n            if (logger.isLoggable(Level.FINEST)) {\n                logger.log(Level.FINEST, \"FDTInternalMonitoring took: \" + (System.nanoTime() - sTime) / 1000000D + \" ms\");\n            }\n\n            if (STATS_LEVEL != null && logger.isLoggable(STATS_LEVEL)) {\n                printStats();\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ InternalMonitoring ] Got Exception \", t);\n        }\n    }\n\n    private static final class WriterAccountingContors {\n\n        private final Lock countersRLock;\n\n        boolean reportOk;\n\n        long lastDtTake;\n\n        long lastDtWrite;\n\n        long lastDtFinishSession;\n\n        long lastDtTotal;\n\n        double procWrite = 0;\n\n        double procFinish = 0;\n\n        double procTake = 0;\n\n        double procOther = 0;\n\n        WriterAccountingContors(final Lock lock) {\n            this.countersRLock = lock;\n            reportOk = false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/FDTReportingTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.disk.DiskReaderManager;\nimport lia.util.net.copy.disk.DiskWriterManager;\nimport lia.util.net.copy.transport.TCPTransportProvider;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Set;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Abstract implementation for internal monitoring and reporting\n *\n * @author ramiro\n */\npublic abstract class FDTReportingTask implements Runnable {\n\n    protected static final DiskReaderManager diskReaderManager = DiskReaderManager.getInstance();\n    protected static final DiskWriterManager diskWriterManager = DiskWriterManager.getInstance();\n    private static final Logger logger = Logger.getLogger(\"lia.util.net.copy.monitoring.FDTReportingTask\");\n\n    public abstract void finishFDTSession(final FDTSession fdtSession);\n\n    public abstract void startFDTSession(final FDTSession fdtSession);\n\n    public HashMap<String, HashMap<String, Double>> getReaderParams() {\n        final HashMap<String, HashMap<String, Double>> monitoringParams = new HashMap<String, HashMap<String, Double>>();\n\n        FDTSession fdtSession = null;\n        Iterator<FDTSession> it = null;\n\n        double rate = 0;\n\n        final Set<FDTSession> fdtSessions = diskReaderManager.getSessions();\n        //Client monitoring - DiskReaderManager\n        it = fdtSessions.iterator();\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \"FDTReportingTask - ReaderSessions: \" + fdtSessions);\n        }\n\n        while (it.hasNext()) {\n            fdtSession = it.next();\n            TCPTransportProvider transportProvider = fdtSession.getTransportProvider();\n            HashMap<String, Double> fdtSessionParams = new HashMap<String, Double>();\n\n            if (transportProvider != null && transportProvider.monitoringTask != null) {\n                rate = (transportProvider.monitoringTask.getTotalRate() * 8D) / Utils.MEGA_BIT;\n                fdtSessionParams.put(\"NET_OUT_Mb\", rate);\n            }\n\n            final FDTSessionMonitoringTask fdtSessionMTask = fdtSession.getMonitoringTask();\n            if (fdtSessionMTask != null) {\n                rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                fdtSessionParams.put(\"DISK_READ_MB\", rate);\n                final double tSize = (fdtSession.getSize() <= 0L) ? 0D : (fdtSession.getSize() / (double) Utils.MEGA_BYTE);\n                final double cSize = (fdtSession.getTotalBytes() <= 0L) ? 0D : (fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE);\n                fdtSessionParams.put(\"TotalMBytes\", tSize);\n                fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                if (fdtSession.getSize() > 0L) {\n                    fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                }\n            } else {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"No FDTSessionMonitoringTask started for fdtSession: \" + fdtSession);\n                }\n            }\n\n            final String monID = fdtSession.getMonID();\n            if (monID != null) {\n                monitoringParams.put(monID, fdtSessionParams);\n            } else {\n                monitoringParams.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n            }\n        }\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \"FDTReportingTask - returning ReaderParams: \" + monitoringParams);\n        }\n\n        return monitoringParams;\n    }\n\n    public HashMap<String, HashMap<String, Double>> getWriterParams() {\n        final HashMap<String, HashMap<String, Double>> monitoringParams = new HashMap<String, HashMap<String, Double>>();\n\n        FDTSession fdtSession = null;\n        Iterator<FDTSession> it = null;\n\n        //Server monitoring - DiskWriterManager\n        it = diskWriterManager.getSessions().iterator();\n\n        double rate = 0;\n\n        while (it.hasNext()) {\n            fdtSession = it.next();\n            TCPTransportProvider transportProvider = fdtSession.getTransportProvider();\n            HashMap<String, Double> fdtSessionParams = new HashMap<String, Double>();\n\n            if (transportProvider != null && transportProvider.monitoringTask != null) {\n                rate = (transportProvider.monitoringTask.getTotalRate() * 8) / Utils.MEGA_BIT;\n                fdtSessionParams.put(\"NET_IN_Mb\", rate);\n            }\n\n            final FDTSessionMonitoringTask fdtSessionMTask = fdtSession.getMonitoringTask();\n            if (fdtSessionMTask != null) {\n                rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                fdtSessionParams.put(\"DISK_WRITE_MB\", rate);\n                final double tSize = (fdtSession.getSize() <= 0L) ? 0D : (fdtSession.getSize() / (double) Utils.MEGA_BYTE);\n                final double cSize = (fdtSession.getTotalBytes() <= 0L) ? 0D : (fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE);\n                fdtSessionParams.put(\"TotalMBytes\", tSize);\n                fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                if (fdtSession.getSize() > 0L) {\n                    fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                }\n            } else {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \"No FDTSessionMonitoringTask started for fdtSession: \" + fdtSession);\n                }\n            }\n\n            final String monID = fdtSession.getMonID();\n            if (monID != null) {\n                monitoringParams.put(monID, fdtSessionParams);\n            } else {\n                monitoringParams.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n            }\n\n        }\n\n        return monitoringParams;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/FDTSessionMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.Accountable;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.monitoring.base.AbstractAccountableMonitoringTask;\nimport lia.util.net.copy.monitoring.lisa.CmdCheckerTask;\nimport lia.util.net.copy.monitoring.lisa.LISAReportingTask;\n\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * @author ramiro\n */\npublic class FDTSessionMonitoringTask extends AbstractAccountableMonitoringTask {\n\n    private final FDTSession fdtSession;\n    private ScheduledFuture<?> cmdCheckerTaskFuture;\n\n    public FDTSessionMonitoringTask(FDTSession fdtSession) {\n        super(new Accountable[]{fdtSession});\n        this.fdtSession = fdtSession;\n    }\n\n    public void startSession() {\n        final LISAReportingTask lisaReportingTask = LISAReportingTask.getInstanceNow();\n        if (lisaReportingTask != null) {\n            final CmdCheckerTask cmdCheckerTask = new CmdCheckerTask(fdtSession, lisaReportingTask, fdtSession);\n            cmdCheckerTaskFuture = Utils.getMonitoringExecService().scheduleWithFixedDelay(cmdCheckerTask, 5, 2, TimeUnit.SECONDS);\n        }\n    }\n\n    public void finishSession() {\n        final LISAReportingTask lisaReportingTask = LISAReportingTask.getInstanceNow();\n        if (lisaReportingTask != null) {\n            lisaReportingTask.finishFDTSession(fdtSession);\n            if (cmdCheckerTaskFuture != null) {\n                cmdCheckerTaskFuture.cancel(true);\n            }\n        }\n    }\n\n    public double getTotalRate() {\n        return getTotalRate(fdtSession);\n    }\n\n    @Override\n    public void rateComputed() {\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/NetSessionMonitoringTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring;\n\nimport lia.util.net.copy.Accountable;\nimport lia.util.net.copy.monitoring.base.AbstractAccountableMonitoringTask;\nimport lia.util.net.copy.transport.TCPTransportProvider;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author ramiro\n */\npublic class NetSessionMonitoringTask extends AbstractAccountableMonitoringTask {\n\n    private static final Logger logger = Logger.getLogger(NetSessionMonitoringTask.class.getName());\n\n    private final TCPTransportProvider transportProvider;\n\n    public NetSessionMonitoringTask(TCPTransportProvider transportProvider) {\n        super(new Accountable[]{transportProvider});\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \"[ NetSessionMonitoringTask ] for transportProvider \" + transportProvider + \" instantiating\", new Exception(\" Debug stack trace\"));\n        }\n\n        this.transportProvider = transportProvider;\n    }\n\n    public double getTotalRate() {\n        return getTotalRate(transportProvider);\n    }\n\n    @Override\n    public void rateComputed() {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/base/AbstractAccountableMonitoringTask.java",
    "content": "package lia.util.net.copy.monitoring.base;\n\nimport lia.util.net.copy.Accountable;\n\nimport java.util.Map;\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Generic class to monitor an {@link Accountable} class\n * <p>\n * The subclasses should only call super.computeRate()\n *\n * @author ramiro\n */\npublic abstract class AbstractAccountableMonitoringTask implements Runnable {\n\n    private static final Logger logger = Logger.getLogger(AbstractAccountableMonitoringTask.class.getName());\n\n    private final ConcurrentHashMap<Accountable, AccountableEntry> accMap = new ConcurrentHashMap<Accountable, AccountableEntry>();\n\n    public AbstractAccountableMonitoringTask(Accountable[] accountableList) {\n        //nehotarat mai esti ... poate vrei mai tarliu\n        if (accountableList == null) {\n            return;\n        }\n        int pos = 0;\n        for (Accountable accountable : accountableList) {\n            try {\n                addIfAbsent(accountable);\n                pos++;\n            } catch (NullPointerException npe) {\n                throw new NullPointerException(\" accountable is null on pos: \" + pos);\n            }\n        }\n    }\n\n    private final void iComputeRate(final Accountable accountable, final AccountableEntry accEntry, final long now) {\n        try {\n            if (accEntry.debug) {\n                logger.log(Level.INFO, \" AbstractAccountableMonitoringTask debug for : \" + accountable + \" BEFORE: \\n:\"\n                        + accEntry);\n            }\n            accEntry.currentUtilBytes = accountable.getUtilBytes();\n            accEntry.currentTotalBytes = accountable.getTotalBytes();\n\n            if (accEntry.lastTimeCalled != 0) {\n                computeRate(accEntry, now);\n            }\n\n            if (accEntry.debug) {\n                logger.log(Level.INFO, \" AbstractAccountableMonitoringTask debug for : \" + accountable + \" AFTER: \\n:\"\n                        + accEntry);\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ AbstractAccountableMonitoringTask ] got exception computing rate for \"\n                    + accountable, t);\n        } finally {\n\n            if (accEntry.lastTimeCalled == 0) {\n                accEntry.startTime = now;\n\n                accEntry.startUtilBytes = accEntry.currentUtilBytes;\n                accEntry.startTotalBytes = accEntry.currentTotalBytes;\n            }\n\n            accEntry.lastTimeCalled = now;\n            accEntry.lastUtilBytes = accEntry.currentUtilBytes;\n            accEntry.lastTotalBytes = accEntry.currentTotalBytes;\n        }\n    }\n\n    public void run() {\n        final long now = System.nanoTime();\n\n        try {\n            for (final Map.Entry<Accountable, AccountableEntry> entry : accMap.entrySet()) {\n                iComputeRate(entry.getKey(), entry.getValue(), now);\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ AbstractAccountableMonitoringTask ] got exception main loop \", t);\n        }\n\n        try {\n            rateComputed();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \" [ AbstractAccountableMonitoringTask ] calling rateComputed\", t);\n        }\n    }\n\n    public abstract void rateComputed();\n\n    protected void resetAllCounters() {\n        for (final AccountableEntry accEntry : accMap.values()) {\n            accEntry.startTime = accEntry.lastTimeCalled = 0;\n\n            accEntry.lastUtilBytes = accEntry.startUtilBytes = accEntry.lastTotalBytes = accEntry.startTotalBytes = 0;\n\n            accEntry.utilRate = accEntry.totalRate = 0;\n\n            accEntry.avgUtilRate = accEntry.avgTotalRate = 0;\n        }\n\n    }\n\n    protected void resetAllCounters(final Accountable accountable) {\n        final AccountableEntry accEntry = getEntry(accountable);\n\n        accEntry.startTime = accEntry.lastTimeCalled = 0;\n\n        accEntry.lastUtilBytes = accEntry.startUtilBytes = accEntry.lastTotalBytes = accEntry.startTotalBytes = 0;\n\n        accEntry.utilRate = accEntry.totalRate = 0;\n\n        accEntry.avgUtilRate = accEntry.avgTotalRate = 0;\n    }\n\n    /**\n     * returns the rate in UM/s\n     */\n    private void computeRate(final AccountableEntry accEntry, final long now) throws Exception {\n        long dt = TimeUnit.NANOSECONDS.toMillis(now - accEntry.lastTimeCalled);\n\n        accEntry.monCount++;\n\n        if (dt <= 0) {\n            logger.log(Level.WARNING, \"[ \" + getClass() + \" ] Timing issues detected on the system. lastTime: \"\n                    + accEntry.lastTimeCalled + \"ns now: \" + now + \"ns. The average and instant rates will be reseted.\");\n            accEntry.startTime = now;\n            accEntry.startUtilBytes = accEntry.currentUtilBytes;\n            accEntry.startTotalBytes = accEntry.currentTotalBytes;\n            return;\n        }\n\n        accEntry.utilRate = ((accEntry.currentUtilBytes - accEntry.lastUtilBytes) * 1000D) / dt;\n        accEntry.totalRate = ((accEntry.currentTotalBytes - accEntry.lastTotalBytes) * 1000D) / dt;\n\n        dt = TimeUnit.NANOSECONDS.toMillis(now - accEntry.startTime);\n\n        if (dt <= 0) {\n            logger.log(Level.WARNING, \"[ \" + getClass() + \" ] Timing issues detected on the system. lastTime: \"\n                    + accEntry.startTime + \"ns now: \" + now + \"ns. The average and instant rates will be reseted.\");\n            accEntry.startTime = now;\n            accEntry.startUtilBytes = accEntry.currentUtilBytes;\n            accEntry.startTotalBytes = accEntry.currentTotalBytes;\n            return;\n        }\n\n        accEntry.avgUtilRate = ((accEntry.currentUtilBytes - accEntry.startUtilBytes) * 1000D) / dt;\n        accEntry.avgTotalRate = ((accEntry.currentTotalBytes - accEntry.startTotalBytes) * 1000D) / dt;\n    }\n\n    protected double getUtilRate(final Accountable accountable) {\n        return getEntry(accountable).utilRate;\n    }\n\n    protected double getTotalRate(final Accountable accountable) {\n        return getEntry(accountable).totalRate;\n    }\n\n    protected double getAvgTotalRate(final Accountable accountable) {\n        return getEntry(accountable).avgTotalRate;\n    }\n\n    protected double getAvgUtilRate(final Accountable accountable) {\n        return getEntry(accountable).avgUtilRate;\n    }\n\n    protected long getMonCount(final Accountable accountable) {\n        return getEntry(accountable).monCount;\n    }\n\n    private AccountableEntry getEntry(final Accountable accountable) {\n        final AccountableEntry accEntry = accMap.get(accountable);\n        if (accEntry == null) {\n            throw new NoSuchElementException(\"No entry for \" + accountable);\n        }\n        return accEntry;\n    }\n\n    protected boolean addIfAbsent(final Accountable accountable) {\n        if (accountable == null) {\n            throw new NullPointerException(\" Accountable cannot be null \");\n        }\n        return (accMap.putIfAbsent(accountable, new AccountableEntry()) == null);\n    }\n\n    protected boolean addIfAbsent(final Accountable accountable, boolean debug) {\n        final AccountableEntry accEntry = new AccountableEntry(debug);\n\n        final boolean bRet = (accMap.putIfAbsent(accountable, accEntry) == null);\n        if (bRet) {\n            iComputeRate(accountable, accEntry, System.nanoTime());\n        }\n        return bRet;\n    }\n\n    protected boolean remove(final Accountable accountable) {\n        return (accMap.remove(accountable) != null);\n    }\n\n    private static class AccountableEntry {\n        final boolean debug;\n        protected long startTime;\n        protected long lastTimeCalled;\n        protected long lastUtilBytes;\n        protected long currentUtilBytes;\n        protected long lastTotalBytes;\n        protected long currentTotalBytes;\n        protected long startUtilBytes;\n        protected long startTotalBytes;\n        protected double utilRate;\n        protected double totalRate;\n        protected double avgUtilRate;\n        protected double avgTotalRate;\n        long monCount;\n\n        AccountableEntry() {\n            this(false);\n        }\n\n        AccountableEntry(boolean debug) {\n            this.debug = debug;\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder sb = new StringBuilder();\n            sb.append(\" startTimeMillis: \").append(startTime).append(\", \");\n            sb.append(\" startUtilBytes: \").append(startUtilBytes).append(\", \");\n            sb.append(\" startTotalBytes: \").append(startTotalBytes).append(\", \");\n            sb.append(\" lastTimeCalled: \").append(lastTimeCalled).append(\", \");\n            sb.append(\" lastUtilBytes: \").append(lastUtilBytes).append(\", \");\n            sb.append(\" currentUtilBytes: \").append(currentUtilBytes).append(\", \");\n            sb.append(\" lastTotalBytes: \").append(lastTotalBytes).append(\", \");\n            sb.append(\" currentTotalBytes: \").append(currentTotalBytes).append(\", \");\n            sb.append(\" utilRate: \").append(utilRate).append(\", \");\n            sb.append(\" totalRate: \").append(totalRate).append(\", \");\n            sb.append(\" avgUtilRate: \").append(avgUtilRate).append(\", \");\n            sb.append(\" avgUtilRate: \").append(avgUtilRate);\n            return sb.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/jmx/DBPoolJMX.java",
    "content": "/*\n * DBPoolJMX.java\n *\n * Created on September 22, 2008, 3:15 PM\n */\npackage lia.util.net.copy.monitoring.jmx;\n\nimport lia.util.net.common.DirectByteBufferPool;\n\nimport javax.management.*;\nimport java.util.Arrays;\n\n/**\n * Class DBPoolJMX; just to test the JMX. Nothing intelligent, for the moment\n *\n * @author ramiro\n */\npublic class DBPoolJMX extends StandardMBean implements DBPoolJMXMBean {\n\n    private final DirectByteBufferPool theRef;\n\n    public DBPoolJMX(DirectByteBufferPool theRef) throws NotCompliantMBeanException {\n        //WARNING Uncomment the following call to super() to make this class compile (see BUG ID 122377)\n        super(DBPoolJMXMBean.class);\n        this.theRef = theRef;\n    }\n\n    @Override\n    public MBeanInfo getMBeanInfo() {\n        MBeanInfo mbinfo = super.getMBeanInfo();\n        return new MBeanInfo(mbinfo.getClassName(),\n                mbinfo.getDescription(),\n                mbinfo.getAttributes(),\n                mbinfo.getConstructors(),\n                mbinfo.getOperations(),\n                getNotificationInfo());\n    }\n\n    public MBeanNotificationInfo[] getNotificationInfo() {\n        return new MBeanNotificationInfo[]{};\n    }\n\n    /**\n     * Override customization hook:\n     * You can supply a customized description for MBeanInfo.getDescription()\n     */\n    @Override\n    protected String getDescription(MBeanInfo info) {\n        return \"DBPoolJMX Description\";\n    }\n\n    /**\n     * Override customization hook:\n     * You can supply a customized description for MBeanAttributeInfo.getDescription()\n     */\n    @Override\n    protected String getDescription(MBeanAttributeInfo info) {\n        String description = null;\n        if (info.getName().equals(\"BufferSize\")) {\n            description = \"Size (in bytes) of the payload buffer in the buffer pool\";\n        } else if (info.getName().equals(\"Capacity\")) {\n            description = \"Total number of buffers allocated\";\n        } else if (info.getName().equals(\"Instance\")) {\n            description = \"Attribute exposed for management\";\n        } else if (info.getName().equals(\"Size\")) {\n            description = \"Number of buffers available in the pool. Just to check leaks in the server. Should have the same value as Capacity when no active connections.\";\n        }\n        return description;\n    }\n\n    /**\n     * Override customization hook:\n     * You can supply a customized description for MBeanParameterInfo.getDescription()\n     */\n    @Override\n    protected String getDescription(MBeanOperationInfo op, MBeanParameterInfo param, int sequence) {\n        if (op.getName().equals(\"totalAllocated\")) {\n            switch (sequence) {\n                default:\n                    return null;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Override customization hook:\n     * You can supply a customized description for MBeanParameterInfo.getName()\n     */\n    @Override\n    protected String getParameterName(MBeanOperationInfo op, MBeanParameterInfo param, int sequence) {\n        if (op.getName().equals(\"totalAllocated\")) {\n            switch (sequence) {\n                default:\n                    return null;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Override customization hook:\n     * You can supply a customized description for MBeanOperationInfo.getDescription()\n     */\n    @Override\n    protected String getDescription(MBeanOperationInfo info) {\n        String description = null;\n        MBeanParameterInfo[] params = info.getSignature();\n        String[] signature = new String[params.length];\n        for (int i = 0; i < params.length; i++) {\n            signature[i] = params[i].getType();\n        }\n        String[] methodSignature;\n        methodSignature = new String[]{};\n        if (info.getName().equals(\"totalAllocated\") && Arrays.equals(signature, methodSignature)) {\n            description = \"Total allocated bytes allocated in NIO buffers. Another cross check. Should be Capacity x Buffer size.\";\n        }\n        return description;\n    }\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getBufferSize() {\n        return theRef.getBufferSize();\n    }\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getCapacity() {\n        return theRef.getCapacity();\n    }\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getSize() {\n        return theRef.getSize();\n    }\n\n    /**\n     * Operation exposed for management\n     *\n     * @return long\n     */\n    public long totalAllocated() {\n        return theRef.totalAllocated();\n    }\n}\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/jmx/DBPoolJMXMBean.java",
    "content": "/*\n * DBPoolJMXMBean.java\n *\n * Created on September 22, 2008, 3:15 PM\n */\npackage lia.util.net.copy.monitoring.jmx;\n\n/**\n * Interface DBPoolJMXMBean\n *\n * @author ramiro\n */\npublic interface DBPoolJMXMBean {\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getBufferSize();\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getCapacity();\n\n    /**\n     * Get Attribute exposed for management\n     */\n    public int getSize();\n\n    /**\n     * Operation exposed for management\n     *\n     * @return long\n     */\n    public long totalAllocated();\n}\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/CmdCheckerTask.java",
    "content": "/*\n * $Id: $\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport lia.util.net.copy.FDTSession;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Periodically checks for remote commands for a specific FDT session\n *\n * @author ramiro\n */\npublic class CmdCheckerTask implements Runnable {\n\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(CmdCheckerTask.class.getName());\n    private final FDTSession fdtSession;\n    private final LISAReportingTask lisaReportingTask;\n    private final LisaCtrlNotifier notifier;\n    private String cmdToSend;\n\n    public CmdCheckerTask(final FDTSession fdtSession, LISAReportingTask lrt, LisaCtrlNotifier notifier) {\n        this.fdtSession = fdtSession;\n        this.lisaReportingTask = lrt;\n        this.notifier = notifier;\n    }\n\n    public void run() {\n        if (cmdToSend == null) {\n            cmdToSend = \"exec FDTClientController getControlParams \" + fdtSession.getMonID();\n            logger.log(Level.INFO, \"[ CmdCheckerTask ] LISA/ML remote command checker started with sessionID: \" + fdtSession.getMonID());\n        }\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"[ CmdCheckerTask ] LISA/ML remote command checker for sessionID: \" + fdtSession.getMonID() + \" running\");\n        }\n\n        try {\n            final String response = lisaReportingTask.lisaMon.sendDirectCommand(cmdToSend);\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"[ CmdCheckerTask ] for sessionID: \" + fdtSession.getMonID() + \" received: \" + response);\n            }\n\n            if (response != null) {\n                notifier.notifyLisaCtrlMsg(response);\n            }\n\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"[ CmdCheckerTask ] Exception in main loop \", t);\n        }\n\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINER, \"[ CmdCheckerTask ] LISA/ML remote command checker for sessionID: \" + fdtSession.getMonID() + \" finished\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/HostPropertiesMonitor.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.logging.Logger;\n\n/**\n * @author Ciprian Dobre\n */\npublic class HostPropertiesMonitor {\n\n    final static String osName = System.getProperty(\"os.name\");\n\n    static {\n        if (osName.indexOf(\"Win\") >= 0) {\n            saveSystemLibrary(HostPropertiesMonitor.class);\n        }\n    }\n\n    ProcReader reader = null;\n    MacHostPropertiesMonitor macHostMonitor = null;\n    String macAddress;\n    HashMap<String, Double> cpuvm;\n    HashMap<String, Double> mem;\n    HashMap<String, Double> disk;\n    int processes;\n    HashMap<String, Double> load;\n    HashMap<String, Double> net;\n\n    public HostPropertiesMonitor(final Logger logger) {\n        if (osName.indexOf(\"Linux\") != -1) {\n            reader = new ProcReader(logger);\n        } else if (osName.indexOf(\"Mac\") != -1) {\n            macHostMonitor = new MacHostPropertiesMonitor(logger);\n        }\n    }\n\n    public static void saveSystemLibrary(Class baseClass) {\n        try {\n            URL url = baseClass.getResource(\"system.dll\"); // here should be the system library package (for jni)\n            File file = new File(\"system.dll\");\n            if (!file.exists()) {\n                byte[] buffer = new byte[1024];\n                URLConnection con = url.openConnection();\n                InputStream in = con.getInputStream();\n                FileOutputStream out = new FileOutputStream(file);\n                int n;\n                while ((n = in.read(buffer, 0, buffer.length)) != -1)\n                    out.write(buffer, 0, n);\n                in.close();\n                out.close();\n            }\n            System.load(file.getAbsolutePath());\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    public native String getMacAddresses();\n\n    public String getMacAddressesCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            return macAddress;\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getMacAddresses();\n        return getMacAddresses();\n    }\n\n    public native void update();\n\n    public void updateCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            try {\n                macAddress = reader.getMACAddress();\n                cpuvm = reader.getCPUVM();\n                mem = reader.getMEM();\n                disk = reader.getDISK();\n                processes = reader.getProcesses();\n                load = reader.getLOAD();\n                net = reader.getNet();\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n            return;\n        }\n        if (osName.indexOf(\"Mac\") != -1) {\n            macHostMonitor.update();\n            return;\n        }\n        update();\n    }\n\n    private final double get(String val) {\n        try {\n            return Double.parseDouble(val);\n        } catch (Throwable t) {\n        }\n        return -1.0;\n    }\n\n    public native String getCpuUsage();\n\n    public double getCpuUsageCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_Usage\");\n        }\n        if (osName.indexOf(\"Mac\") != -1) {\n            return get(macHostMonitor.getCpuUsage());\n        }\n        return get(getCpuUsage());\n    }\n\n    public native String getCpuUSR();\n\n    public double getCpuUSRCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_usr\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getCpuUSR());\n        return get(getCpuUSR());\n    }\n\n    public native String getCpuSYS();\n\n    public double getCpuSYSCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_sys\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getCpuSYS());\n        return get(getCpuSYS());\n    }\n\n    public native String getCpuNICE();\n\n    public double getCpuNICECall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_nice\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getCpuNICE());\n        return get(getCpuNICE());\n    }\n\n    public native String getCpuIDLE();\n\n    public double getCpuIDLECall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_idle\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getCpuIDLE());\n        return get(getCpuIDLE());\n    }\n\n    public double getCPUIoWaitCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_iowait\");\n        }\n        return -1.0;\n    }\n\n    public double getCPUIntCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_int\");\n        }\n        return -1.0;\n    }\n\n    public double getCPUSoftIntCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_softint\");\n        }\n        return -1.0;\n    }\n\n    public double getCPUStealCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"CPU_steal\");\n        }\n        return -1.0;\n    }\n\n    public native String getPagesIn();\n\n    public double getPagesInCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"Page_in\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getPagesIn());\n        return get(getPagesIn());\n    }\n\n    public native String getPagesOut();\n\n    public double getPagesOutCall() {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"Page_out\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getPagesOut());\n        return get(getPagesOut());\n    }\n\n    /**\n     * Get swap in - works in linux flavors only\n     */\n    public double getSwapInCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"Swap_in\");\n        }\n        return -1.0;\n    }\n\n    public double getSwapOutCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (cpuvm == null) return -1.0;\n            return cpuvm.get(\"Swap_out\");\n        }\n        return -1.0;\n    }\n\n    public native String getMemUsage();\n\n    public double getMemUsageCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (mem == null) return -1.0;\n            return mem.get(\"MemUsage\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getMemUsage());\n        return get(getMemUsage());\n    }\n\n    public native String getMemUsed();\n\n    public double getMemUsedCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (mem == null) return -1.0;\n            return mem.get(\"MemUsed\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getMemUsed());\n        return get(getMemUsed());\n    }\n\n    public native String getMemFree();\n\n    public double getMemFreeCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (mem == null) return -1.0;\n            return mem.get(\"MemFree\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getMemFree());\n        return get(getMemFree());\n    }\n\n    public native String getDiskIO();\n\n    public double getDiskIOCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (disk == null) return -1.0;\n            return disk.get(\"DiskIO\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getDiskIO());\n        return get(getDiskIO());\n    }\n\n    public native String getDiskTotal();\n\n    public double getDiskTotalCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (disk == null) return -1.0;\n            return disk.get(\"DiskTotal\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getDiskTotal());\n        return get(getDiskTotal());\n    }\n\n    public native String getDiskUsed();\n\n    public double getDiskUsedCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (disk == null) return -1.0;\n            return disk.get(\"DiskUsed\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getDiskUsed());\n        return get(getDiskUsed());\n    }\n\n    public native String getDiskFree();\n\n    public double getDiskFreeCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (disk == null) return -1.0;\n            return disk.get(\"DiskFree\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getDiskFree());\n        return get(getDiskFree());\n    }\n\n    public native String getNoProcesses();\n\n    public int getNoProcessesCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            return processes;\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return (int) get(macHostMonitor.getNoProcesses());\n        return (int) get(getNoProcesses());\n    }\n\n    public native String getLoad1();\n\n    public double getLoad1Call() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (load == null) return -1.0;\n            return load.get(\"Load1\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getLoad1());\n        return get(getLoad1());\n    }\n\n    public native String getLoad5();\n\n    public double getLoad5Call() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (load == null) return -1.0;\n            return load.get(\"Load5\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getLoad5());\n        return get(getLoad5());\n    }\n\n    public native String getLoad15();\n\n    public double getLoad15Call() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (load == null) return -1.0;\n            return load.get(\"Load15\");\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getLoad15());\n        return get(getLoad15());\n    }\n\n    public native String[] getNetInterfaces();\n\n    public String[] getNetInterfacesCall() {\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (net == null) return null;\n            final String[] ret = new String[net.size() / 2];\n            int i = 0;\n            for (Iterator<String> it = net.keySet().iterator(); it.hasNext() && i < ret.length; ) {\n                final String key = it.next();\n                if (key.startsWith(\"In_\")) {\n                    ret[i] = key.substring(3);\n                    i++;\n                }\n            }\n            while (i < ret.length) ret[i++] = null;\n            return ret;\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return macHostMonitor.getNetInterfaces();\n        return getNetInterfaces();\n    }\n\n    public native String getNetIn(String ifName);\n\n    public double getNetInCall(String ifName) {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (net == null || !net.containsKey(\"In_\" + ifName)) return -1.0;\n            return net.get(\"In_\" + ifName);\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getNetIn(ifName));\n        return get(getNetIn(ifName));\n    }\n\n    public native String getNetOut(String ifName);\n\n    public double getNetOutCall(String ifName) {\n\n        if (osName.indexOf(\"Linux\") != -1) {\n            if (net == null || !net.containsKey(\"Out_\" + ifName)) return -1.0;\n            return net.get(\"Out_\" + ifName);\n        }\n        if (osName.indexOf(\"Mac\") != -1)\n            return get(macHostMonitor.getNetOut(ifName));\n        return get(getNetOut(ifName));\n    }\n\n} // end of class HostPropertiesMonitor\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/LISAReportingTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.FDTWriterSession;\nimport lia.util.net.copy.monitoring.FDTReportingTask;\nimport lia.util.net.copy.monitoring.FDTSessionMonitoringTask;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class is used to send the internal monitoring informations back to LISA/MonALISA\n * over an (XDR) Socket\n *\n * @author ramiro\n */\npublic class LISAReportingTask extends FDTReportingTask {\n\n    private static final Logger logger = Logger.getLogger(LISAReportingTask.class.getName());\n    private static LISAReportingTask _thisInstance;\n    private final String lisaHost;\n    private final int lisaPort;\n    volatile public MonClient lisaMon;\n    private boolean errorReported = false;\n\n    private LISAReportingTask(String lisaHost, int lisaPort) {\n        this.lisaHost = lisaHost;\n        this.lisaPort = lisaPort;\n        setupMonClient();\n    }\n\n    public static final LISAReportingTask initInstance(String lisaHost, int lisaPort) {\n        synchronized (LISAReportingTask.class) {\n            if (_thisInstance == null) {\n                _thisInstance = new LISAReportingTask(lisaHost, lisaPort);\n                LISAReportingTask.class.notifyAll();\n            }\n        }\n        return _thisInstance;\n    }\n\n    public static final LISAReportingTask getInstanceNow() {\n        synchronized (LISAReportingTask.class) {\n            return _thisInstance;\n        }\n    }\n\n    public static final LISAReportingTask getInstance() {\n        synchronized (LISAReportingTask.class) {\n            while (_thisInstance == null) {\n                try {\n                    LISAReportingTask.class.wait(5000);\n                    logger.log(Level.WARNING, \" getInstace timeout on LISAReporting task ... \");\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n            return _thisInstance;\n        }\n    }\n\n    private void publishStartFinishParams(final FDTSession fdtSession) {\n        if (fdtSession != null) {\n            try {\n                final HashMap<String, HashMap<String, Double>> lisaParams = new HashMap<String, HashMap<String, Double>>();\n                final HashMap<String, Double> fdtSessionParams = new HashMap<String, Double>();\n                final FDTSessionMonitoringTask fdtSessionMTask = fdtSession.getMonitoringTask();\n\n                if (fdtSessionMTask != null) {\n                    if (fdtSession instanceof FDTWriterSession) {\n                        final double rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"DISK_WRITE_MB\", rate);\n                        final double tSize = fdtSession.getSize() / (double) Utils.MEGA_BYTE;\n                        final double cSize = fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"TotalMBytes\", tSize);\n                        fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                        fdtSessionParams.put(\"Status\", (double) fdtSession.getCurrentStatus());\n\n                        if (fdtSession.getSize() != 0) {\n                            fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                        }\n\n                        final String monID = fdtSession.getMonID();\n                        if (monID != null) {\n                            lisaParams.put(monID, fdtSessionParams);\n                        } else {\n                            lisaParams.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n                        }\n\n                        if (lisaParams.size() > 0) {\n                            if (logger.isLoggable(Level.FINE)) {\n                                logger.log(Level.FINE, \" Sending to LISA :- Client Params: \" + lisaParams);\n                            }\n                            for (Map.Entry<String, HashMap<String, Double>> entry : lisaParams.entrySet()) {\n                                HashMap<String, Double> hToSend = entry.getValue();\n                                if (hToSend.size() > 0) {\n                                    lisaMon.sendServerParameters(entry.getKey(), hToSend);\n                                }\n                            }\n                        }\n\n                    } else if (fdtSession instanceof FDTReaderSession) {\n                        final double rate = fdtSessionMTask.getTotalRate() / Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"DISK_READ_MB\", rate);\n                        final double tSize = fdtSession.getSize() / (double) Utils.MEGA_BYTE;\n                        final double cSize = fdtSession.getTotalBytes() / (double) Utils.MEGA_BYTE;\n                        fdtSessionParams.put(\"TotalMBytes\", tSize);\n                        fdtSessionParams.put(\"TransferredMBytes\", cSize);\n                        if (fdtSession.getSize() != 0) {\n                            fdtSessionParams.put(\"TransferRatio\", (cSize * 100) / tSize);\n                        }\n                        fdtSessionParams.put(\"Status\", (double) fdtSession.getCurrentStatus());\n\n                        final String monID = fdtSession.getMonID();\n                        if (monID != null) {\n                            lisaParams.put(monID, fdtSessionParams);\n                        } else {\n                            lisaParams.put(fdtSession.getRemoteAddress().getHostAddress() + \":\" + fdtSession.getRemotePort(), fdtSessionParams);\n                        }\n\n                        if (lisaParams.size() > 0) {\n                            if (logger.isLoggable(Level.FINE)) {\n                                logger.log(Level.FINE, \" Sending to LISA :- Server Params: \" + lisaParams);\n                            }\n                            for (Map.Entry<String, HashMap<String, Double>> entry : lisaParams.entrySet()) {\n                                HashMap<String, Double> hToSend = entry.getValue();\n                                if (hToSend.size() > 0) {\n                                    lisaMon.sendClientParameters(entry.getKey(), hToSend);\n                                }\n                            }\n                        }\n\n                    } else {\n                        logger.log(Level.WARNING, \"[ERROR] FDT Session is not an \\\"instanceof\\\" FDTWriterSession or FDTReaderSession!!!\");\n                        return;\n                    }\n                } else {\n                    logger.log(Level.WARNING, \"[ERROR] FDTSessionMonitoringTask is null in finishFDTSession(fdtSession)!!!\");\n                }\n\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got expcetion notifying last params for \" + fdtSession.sessionID(), t);\n            }\n        } else {\n            logger.log(Level.WARNING, \"[ERROR] FDT Session is null in finishFDTSession(fdtSession)!!!\");\n        }\n    }\n\n    public void startFDTSession(final FDTSession fdtSession) {\n        publishStartFinishParams(fdtSession);\n    }\n\n    public void finishFDTSession(final FDTSession fdtSession) {\n        publishStartFinishParams(fdtSession);\n    }\n\n    private void setupMonClient() {\n        try {\n            lisaMon = new MonClient(lisaHost, lisaPort);\n        } catch (Throwable t) {\n            if (!errorReported) {\n                logger.log(Level.WARNING, \" Cannot connect to lisa\", t);\n            } else {\n                logger.log(Level.FINER, \" Cannot connect to lisa\", t);\n            }\n            errorReported = true;\n        }\n    }\n\n    public void run() {\n        try {\n            if (lisaMon == null) {\n                setupMonClient();\n            }\n\n            if (lisaMon == null) return;\n\n            errorReported = false;\n\n            HashMap<String, HashMap<String, Double>> lisaParams = getReaderParams();\n\n            if (lisaParams.size() > 0) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \" Sending to LISA :- Client Params: \" + lisaParams);\n                }\n                for (Map.Entry<String, HashMap<String, Double>> entry : lisaParams.entrySet()) {\n                    HashMap<String, Double> hToSend = entry.getValue();\n                    if (hToSend.size() > 0) {\n                        lisaMon.sendClientParameters(entry.getKey(), hToSend);\n                    }\n                }\n            }\n\n            lisaParams = getWriterParams();\n\n            double totalNet = 0;\n            double totalDisk = 0;\n\n            if (lisaParams.size() > 0) {\n                if (logger.isLoggable(Level.FINE)) {\n                    logger.log(Level.FINE, \" Sending to LISA :- Server Params: \" + lisaParams);\n                }\n                for (Map.Entry<String, HashMap<String, Double>> entry : lisaParams.entrySet()) {\n                    HashMap<String, Double> hToSend = entry.getValue();\n                    if (hToSend.size() > 0) {\n                        Double dToAdd = hToSend.get(\"NET_IN_Mb\");\n                        if (dToAdd != null) {\n                            totalNet += dToAdd;\n                        }\n\n                        dToAdd = hToSend.get(\"DISK_WRITE_MB\");\n                        if (dToAdd != null) {\n                            totalDisk += dToAdd;\n                        }\n\n                        lisaMon.sendServerParameters(entry.getKey(), hToSend);\n                    }\n                }\n            }\n\n            if (Config.getInstance().getHostName() == null) {\n                HashMap<String, Double> localParams = new HashMap<String, Double>();\n                localParams.put(\"CLIENTS_NO\", (double) lisaParams.size());\n                localParams.put(\"DISK_WRITE_MB\", totalDisk);\n                localParams.put(\"NET_IN_Mb\", totalNet);\n\n                lisaMon.sendServerParameters(\"FDT_PARAMS\", localParams);\n            }\n\n//            HashMap<String, Double> fdtLisaParams = FDTInternalMonitoringTask.getInstance().getLisaParams();            \n//            \n//            String key = \"FDT_MON:\";\n//            if(Config.getInstance().getHostName() == null) {\n//                key += Config.getInstance().getPort();\n//            } else {\n//                String rPort = \"\";\n//                it = diskReaderManager.getSessions().iterator();\n//                while(it.hasNext()) {\n//                    fdtSession = it.next();\n//                    rPort += fdtSession.getLocalPort();\n//                }\n//\n//                it = diskWriterManager.getSessions().iterator();\n//                while(it.hasNext()) {\n//                    fdtSession = it.next();\n//                    rPort += fdtSession.getLocalPort();\n//                }\n//                \n//                if(rPort.length() == 0) {\n//                    rPort = \"UNK\";\n//                }\n//                \n//                key += rPort;\n//            }\n//\n//            if(logger.isLoggable(Level.FINER)) {\n//                logger.log(Level.FINER, \"FDT Params: \" + fdtLisaParams + \" Key: \" + key);\n//            }\n//            \n//            lisaMon.sendServerParameters(key, fdtLisaParams);\n\n        } catch (Throwable t) {\n            logger.log(Level.INFO, \" LISAReportingTask got exception:\", t);\n        }\n    }\n\n    public void sendClientNow(String key, HashMap<String, Double> params) throws Exception {\n        lisaMon.sendClientParameters(key, params);\n    }\n\n    public void sendServerNow(String key, HashMap<String, Double> params) throws Exception {\n        lisaMon.sendServerParameters(key, params);\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/LisaCtrlNotifier.java",
    "content": "/*\n * $Id: $\n */\npackage lia.util.net.copy.monitoring.lisa;\n\n/**\n * Receiver of remote commands from LISA/ML modules\n *\n * @author ramiro\n */\npublic interface LisaCtrlNotifier {\n\n    public void notifyLisaCtrlMsg(String lisaCtrlMsg);\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/MacHostPropertiesMonitor.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport lia.util.net.copy.monitoring.lisa.cmdExec.CommandResult;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Gregory Denis\n * @author Ciprian Dobre\n */\npublic class MacHostPropertiesMonitor {\n\n    protected static final Object lock = new Object();\n    protected static int ptnr = 0;\n    protected final Logger logger;\n    protected String[] networkInterfaces;\n    protected String activeInterface;\n    protected String cpuUsage = \"0\";\n    protected String cpuUSR = \"0\";\n    protected String cpuSYS = \"0\";\n    protected String cpuIDLE = \"0\";\n    protected String nbProcesses = \"0\";\n    protected String load1 = \"0\";\n    protected String load5 = \"0\";\n    protected String load15 = \"0\";\n    protected String memUsed = \"0\";\n    protected String memFree = \"0\";\n    protected String memUsage = \"0\";\n    protected String netIn = \"0\";\n    protected String netOut = \"0\";\n    protected String pagesIn = \"0\";\n    protected String pagesOut = \"0\";\n    protected String macAddress = \"unknown\";\n    protected String diskIO = \"0\";\n    protected String diskIn = \"0\";\n    protected String diskOut = \"0\";\n    protected String diskFree = \"0\";\n    protected String diskUsed = \"0\";\n    protected String diskTotal = \"0\";\n    protected String command = \"\";\n    protected cmdExec execute = null;\n    protected String sep = null;\n\n    public MacHostPropertiesMonitor(final Logger logger) {\n\n        this.logger = logger;\n\n        execute = cmdExec.getInstance();\n        sep = System.getProperty(\"file.separator\");\n        // get the network interfaces up\n        command = sep + \"sbin\" + sep + \"ifconfig -l -u\";\n        CommandResult cmdRes = execute.executeCommand(command, \"lo0\", 3 * 1000L);\n        String result = cmdRes.getOutput();\n        // System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            logger.warning(command + \": No result???\");\n        } else {\n            int where = result.indexOf(\"lo0\");\n            networkInterfaces = result.substring(where + 3, result.length()).replaceAll(\"  \", \" \").trim().split(\" \");\n\n            // get the currently used Mac Address\n            for (int i = 0; i < networkInterfaces.length; i++) {\n                String current = networkInterfaces[i];\n                command = sep + \"sbin\" + sep + \"ifconfig \" + current;\n                cmdRes = execute.executeCommand(command, current, 3 * 1000L);\n                result = cmdRes.getOutput();\n                // System.out.println(command + \" = \" + result);\n                if (result == null || result.equals(\"\")) {\n                    logger.warning(command + \": No result???\");\n                } else {\n                    if (result.indexOf(\"inet \") != -1) {\n                        int pointI = result.indexOf(\"ether\");\n                        int pointJ = result.indexOf(\"media\", pointI);\n                        macAddress = result.substring(pointI + 5, pointJ).trim();\n                        // System.out.println(\"Mac Address:\" + macAddress);\n                        activeInterface = current;\n                    }\n                }\n            }\n        }\n\n        // get the disk information\n        command = sep + \"bin\" + sep + \"df -k -h \" + sep;\n        cmdRes = execute.executeCommand(command, \"/dev\", 3 * 1000L);\n        result = cmdRes.getOutput();\n        // System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            logger.warning(command + \": No result???\");\n        } else {\n            parseDf(result);\n        }\n\n        update();\n    }\n\n    public String getMacAddresses() {\n        return macAddress;\n    }\n\n    public void update() {\n\n        if (execute == null) {\n            execute = cmdExec.getInstance();\n        }\n\n        // get CPU, load, Mem, Pages, Processes from '/usr/bin/top'\n        command = sep + \"usr\" + sep + \"bin\" + sep + \"top -d -l2 -n1 -F -R -X\";\n        CommandResult cmdRes = execute.executeCommand(command, \"PID\", 2, 100 * 1000L);\n        String result = cmdRes.getOutput();\n        // System.out.println(command + \" = \"+ result);\n        if (result == null || result.equals(\"\")) {\n            logger.warning(\"No result???\");\n        } else {\n            parseTop(result);\n        }\n    }\n\n    // private void parseIfConfig(String toParse) {\n    //\n    // //System.out.println(\"result of ifconfig:\" + toParse);\n    // if (toParse.indexOf(\"inet \") != -1) {\n    // int pointI = toParse.indexOf(\"ether\");\n    // int pointJ = toParse.indexOf(\"media\", pointI);\n    // macAddress = toParse.substring(pointJ + 5, pointI).trim();\n    // System.out.println(\"Mac Address:\" + macAddress);\n    // }\n    // }\n\n    private void parseDf(String toParse) {\n\n        // System.out.println(\"result of df -k -h /:\" + toParse);\n\n        int pointI = toParse.indexOf(\"/dev/\");\n        int pointJ = 0;\n        int pointK = 0;\n\n        // Get the size of the root disk\n        try {\n            pointJ = toParse.indexOf(\" \", pointI);\n            pointK = indexOfUnitLetter(toParse, pointJ);\n            diskTotal = toParse.substring(pointJ, pointK).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the capacity used\n        try {\n            pointI = toParse.indexOf(\" \", pointK);\n            pointJ = indexOfUnitLetter(toParse, pointI);\n            diskUsed = toParse.substring(pointI, pointJ).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the free space\n        try {\n            pointK = toParse.indexOf(\" \", pointJ);\n            pointI = indexOfUnitLetter(toParse, pointK);\n            diskFree = toParse.substring(pointK, pointI).trim();\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n\t\t/*\n         * System.out.println( \"Disk: Total:\" + diskTotal + \" Used:\" + diskUsed + \" Free:\" + diskFree);\n\t\t */\n    }\n\n    private int indexOfUnitLetter(String inside, int from) {\n\n        int temp = inside.indexOf('K', from);\n        if (temp == -1 || (temp - from > 10)) {\n            temp = inside.indexOf('M', from);\n            if (temp == -1 || (temp - from > 10)) {\n                temp = inside.indexOf('G', from);\n                if (temp == -1 || (temp - from > 10)) {\n                    temp = inside.indexOf('B', from);\n                    if (temp == -1 || (temp - from > 10)) {\n                        temp = inside.indexOf('T', from);\n                        if (temp == -1 || (temp - from > 10)) {\n                            temp = inside.indexOf('b', from);\n                            if (temp - from > 10)\n                                temp = -1;\n                        }\n                    }\n                }\n            }\n        }\n        return temp;\n    }\n\n    private int lastIndexOfUnitLetter(String inside, int from) {\n\n        int temp = inside.lastIndexOf('K', from);\n        if (temp == -1 || (from - temp > 10)) {\n            temp = inside.lastIndexOf('M', from);\n            if (temp == -1 || (from - temp > 10)) {\n                temp = inside.lastIndexOf('G', from);\n                if (temp == -1 || (from - temp > 10)) {\n                    temp = inside.lastIndexOf('B', from);\n                    if (temp == -1 || (from - temp > 10)) {\n                        temp = inside.lastIndexOf('T', from);\n                        if (temp == -1 || (from - temp > 10)) {\n                            temp = inside.lastIndexOf('b', from);\n                            if (from - temp > 10)\n                                temp = -1;\n                        }\n                    }\n                }\n            }\n        }\n        return temp;\n    }\n\n    // private double howMuchKiloBytes(char a) {\n    //\n    // switch (a) {\n    // case 'T' :\n    // return 1073741824.0;\n    // case 'G' :\n    // return 1048576.0;\n    // case 'M' :\n    // return 1024.0;\n    // case 'K' :\n    // return 1.0;\n    // case 'B' :\n    // return 0.0009765625;\n    // default :\n    // return 1.0;\n    // }\n    // }\n\n    private double howMuchMegaBytes(char a) {\n\n        switch (a) {\n            case 'T':\n                return 1048576.0;\n            case 'G':\n                return 1024.0;\n            case 'M':\n                return 1.0;\n            case 'K':\n                return 0.0009765625;\n            case 'B':\n                return 0.0000009537;\n            default:\n                return 1.0;\n        }\n    }\n\n    private void parseTop(String toParse) {\n\n        // System.out.println(\"\\n******\\n\"+toParse+\"\\n********\\n\");\n\n        int pointA = 0;\n        int pointB = 0;\n        int unitPos = 0;\n        double sum = 0.0;\n\n        // Get number of total Processes\n        try {\n            pointA = toParse.indexOf(\"Procs:\");\n            // System.out.println(\"First Procs at \" + pointA);\n            pointA = toParse.indexOf(\"Procs:\", pointA + 6) + 6;\n            // System.out.println(\"Second Procs at \" + pointA);\n            pointB = toParse.indexOf(\",\", pointA + 1);\n            nbProcesses = toParse.substring(pointA, pointB).trim();\n            // System.out.println(nbProcesses + \" processes\");\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get the loads...\n        try {\n            pointA = toParse.indexOf(\"LoadAvg:\", pointA);\n            pointA += 9;\n            pointB = toParse.indexOf(\",\", pointA);\n            load1 = toParse.substring(pointA, pointB).trim();\n            pointA = toParse.indexOf(\",\", pointB + 1);\n            load5 = toParse.substring(pointB + 1, pointA).trim();\n            pointB = toParse.indexOf(\"CPU:\", pointA + 1);\n            pointB = toParse.lastIndexOf(\".\", pointB);\n            load15 = toParse.substring(pointA + 1, pointB).trim();\n            // System.out.println(\"load: [\" + load1 + \"][\" + load5 + \"][\" + load15 + \"]\");\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get CPUs...\n        try {\n            pointB = toParse.indexOf(\"CPU:\", pointB + 1) + 4;\n            pointA = toParse.indexOf(\"% user\", pointB);\n            cpuUSR = toParse.substring(pointB, pointA).trim();\n            pointA = toParse.indexOf(\",\", pointA);\n            pointB = toParse.indexOf(\"% sys\", pointA + 1);\n            cpuSYS = toParse.substring(pointA + 1, pointB).trim();\n            pointA = toParse.indexOf(\",\", pointB);\n            pointB = toParse.indexOf(\"% idle\", pointA + 1);\n            cpuIDLE = toParse.substring(pointA + 1, pointB).trim();\n            sum = 100.0 - Double.parseDouble(cpuIDLE);\n            cpuUsage = String.valueOf(sum);\n\t\t\t/*\n\t\t\t * System.out.println(\"Cpu Usage:\" + cpuUsage + \" user:\" + cpuUSR + \" sys:\" + cpuSYS + \" idle:\" + cpuIDLE);\n\t\t\t */\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Get Mem...\n        try {\n            pointA = toParse.indexOf(\"PhysMem\", pointB);\n            pointA += 8;\n            pointB = toParse.indexOf(\"M used\", pointA);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            memUsed = toParse.substring(pointA + 1, pointB).trim();\n            pointB = toParse.indexOf(\"M free\", pointB);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            memFree = toParse.substring(pointA + 1, pointB).trim();\n            // System.out.println(\"Mem Used:\"+memUsed+\"M Free:\"+memFree+\"M\");\n            sum = Double.parseDouble(memUsed) + Double.parseDouble(memFree);\n            double percentage = Integer.parseInt(memUsed) / sum * 100;\n            memUsage = String.valueOf(percentage);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n\n        // Pages In/Out...\n        try {\n            pointA = toParse.indexOf(\"VirtMem:\", pointB + 6);\n            pointB = toParse.indexOf(\"pagein\", pointA);\n            pointA = toParse.lastIndexOf(\",\", pointB);\n            pagesIn = toParse.substring(pointA + 1, pointB).trim();\n            pointA = toParse.indexOf(\"pageout\", pointB);\n            pointB = toParse.lastIndexOf(\",\", pointA);\n            pagesOut = toParse.substring(pointB + 1, pointA).trim();\n            // System.out.println(\"Pages In:\" + pagesIn + \" Out\" + pagesOut);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n            logger.warning(\"Can't find pages in :\" + toParse);\n        }\n        ;\n\n        // Get Network IO...\n        try {\n            pointA = toParse.indexOf(\"Networks:\", pointB) + 9;\n            pointB = toParse.indexOf(\"data =\", pointA) + 6;\n            pointA = toParse.indexOf(\"in\", pointB);\n            unitPos = lastIndexOfUnitLetter(toParse, pointA);\n            netIn = toParse.substring(pointB, unitPos).trim();\n            // System.out.print(\"Net In:\" + netIn);\n            double factor = howMuchMegaBytes((toParse.substring(unitPos, unitPos + 1).toCharArray())[0]);\n            netIn = String.valueOf(Double.parseDouble(netIn) * factor * 4);\n            pointB = toParse.indexOf(\"out\", pointA);\n            unitPos = lastIndexOfUnitLetter(toParse, pointB);\n            factor = howMuchMegaBytes((toParse.substring(unitPos, unitPos + 1).toCharArray())[0]);\n            netOut = toParse.substring(pointA + 3, unitPos).trim();\n            // System.out.println(\"Net Out:\" + netOut);\n            netOut = String.valueOf(Double.parseDouble(netOut) * factor);\n            // System.out.println(\"Network In:\" + netIn + \" OUT:\" + netOut);\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n            logger.log(Level.INFO, \"Got exception\", e);\n        }\n        ;\n\n        // Get Disks IO...\n        try {\n            pointB = toParse.indexOf(\"Disks:\", pointA) + 6;\n            pointA = toParse.indexOf(\"data =\", pointB) + 6;\n            pointB = toParse.indexOf(\"in,\", pointA);\n            unitPos = lastIndexOfUnitLetter(toParse, pointB);\n            diskIn = toParse.substring(pointA, unitPos).trim();\n            pointA = toParse.indexOf(\"out\", pointB);\n            unitPos = lastIndexOfUnitLetter(toParse, pointA);\n            diskOut = toParse.substring(pointB + 3, unitPos).trim();\n\n            // System.out.println(\"diskIO In:\" + diskIn + \" Out:\" + diskOut);\n            diskIO = diskOut;\n        } catch (java.lang.StringIndexOutOfBoundsException e) {\n        }\n        ;\n    }\n\n    public String getCpuUsage() {\n        return cpuUsage;\n    }\n\n    public String getCpuUSR() {\n        return cpuUSR;\n    }\n\n    public String getCpuSYS() {\n        return cpuSYS;\n    }\n\n    public String getCpuNICE() {\n        return \"0\";\n    }\n\n    public String getCpuIDLE() {\n        return cpuIDLE;\n    }\n\n    public String getPagesIn() {\n        return pagesIn;\n    }\n\n    public String getPagesOut() {\n        return pagesOut;\n    }\n\n    public String getMemUsage() {\n        return memUsage;\n    }\n\n    public String getMemUsed() {\n        return memUsed;\n    }\n\n    public String getMemFree() {\n        return memFree;\n    }\n\n    public String getDiskIO() {\n        return diskIO;\n    }\n\n    public String getDiskTotal() {\n        return diskTotal;\n    }\n\n    public String getDiskUsed() {\n        return diskUsed;\n    }\n\n    public String getDiskFree() {\n        return diskFree;\n    }\n\n    public String getNoProcesses() {\n        return nbProcesses;\n    }\n\n    public String getLoad1() {\n        return load1;\n    }\n\n    public String getLoad5() {\n        return load5;\n    }\n\n    public String getLoad15() {\n        return load15;\n    }\n\n    public String[] getNetInterfaces() {\n        return networkInterfaces;\n    }\n\n    public String getNetIn(String ifName) {\n        if (ifName.equalsIgnoreCase(activeInterface))\n            return netIn;\n        else\n            return \"0\";\n    }\n\n    public String getNetOut(String ifName) {\n        if (ifName.equalsIgnoreCase(activeInterface))\n            return netOut;\n        return \"0\";\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/MonClient.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport lia.util.net.copy.monitoring.lisa.xdr.XDRClient;\n\nimport java.util.Map;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Adrian Muraru\n */\npublic class MonClient {\n\n    private static final Logger logger = Logger.getLogger(MonClient.class.getName());\n    XDRClient lisaClient = null;// XDRClient.getClient(\"store1.uslhcnet.org\", 5001);\n    private String lisaHost;\n    private int lisaPort;\n\n    /**\n     * @param lisaHost: lisa host\n     * @param lisaPort  :\n     *                  lisa XDR port\n     */\n    public MonClient(String lisaHost, int lisaPort) throws Exception {\n        this.lisaHost = lisaHost;\n        this.lisaPort = lisaPort;\n        checkAndInitLisaClient();\n    }\n\n    /**\n     * Sends information related to FDT Client\n     *\n     * @param id:         transfer identifier (in ML this will be the Node under which the values are reported)\n     * @param parameters: paramters map\n     * @throws Exception\n     */\n    public void sendClientParameters(String id, Map<String, Double> parameters) throws Exception {\n        try {\n            StringBuilder sbCommand = new StringBuilder(\"exec FDTClient monitorTransfer \" + id);\n            if (parameters != null) {\n                for (Map.Entry<String, Double> entry : parameters.entrySet()) {\n                    sbCommand.append(\" \").append(entry.getKey()).append(\" \").append(entry.getValue());\n                }\n            }\n            String sResult = sendDirectCommand(sbCommand.toString());\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"Send CLIENT params Result: \" + sResult);\n            }\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINEST, \" Got exception sending client params to LISA\", t);\n            }\n        }\n    }\n\n    /**\n     * Sends information related to FDT Server\n     *\n     * @param id:         transfer identifier (in ML this will be the Node under which the values are reported)\n     * @param parameters: paramters map\n     * @throws Exception\n     */\n    public void sendServerParameters(String id, Map<String, Double> parameters) throws Exception {\n        try {\n            StringBuilder sbCommand = new StringBuilder(\"exec FDTServer monitorTransfer \" + id);\n            if (parameters != null) {\n                for (Map.Entry<String, Double> entry : parameters.entrySet()) {\n                    sbCommand.append(\" \").append(entry.getKey()).append(\" \").append(entry.getValue());\n                }\n            }\n            String sResult = sendDirectCommand(sbCommand.toString());\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"Send SERVER params Result: \" + sResult);\n            }\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINEST, \" Got exception sending server params to LISA\", t);\n            }\n        }\n    }\n\n    private synchronized void checkAndInitLisaClient() {\n        if (this.lisaClient == null || this.lisaClient.isClosed()) {\n            this.lisaClient = XDRClient.getClient(lisaHost, lisaPort);\n        }\n    }\n\n    public String sendDirectCommand(final String cmd) throws Exception {\n        checkAndInitLisaClient();\n        if (lisaClient != null) {\n            return lisaClient.sendCommand(cmd);\n        }\n\n        throw new Exception(\"Unable to connect to LISA / ML modules\");\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/ProcReader.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport lia.util.net.copy.monitoring.lisa.cmdExec.CommandResult;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.text.NumberFormat;\nimport java.util.*;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Utility class that monitors the internals of the Linux box...\n *\n * @author Ciprian Dobre\n */\npublic class ProcReader {\n\n    final static NumberFormat nf = NumberFormat.getInstance();\n    /**\n     * PARAMETER UNITS\n     */\n\n//\t( PARAM, UNIT):\n//\t(\"CpuUsage\", \"%\")\n//\t(\"CpuUsr\", \"%\")\n//\t(\"CpuSys\", \"%\")\n//\t(\"CpuNice\", \"%\")\n//\t(\"CpuIdle\", \"%\")\n//\t(\"CpuIoWait\", \"%\")\n//\t(\"CpuInt\", \"%\")\n//\t(\"CpuSoftInt\", \"%\")\n//\t(\"CpuSteal\", \"%\")\n//\t(\"PagesIn\", \"\")\n//\t(\"PagesOut\", \"\")\n//\t(\"SwapIn\", \"\")\n//\t(\"SwapOut\", \"\")\n//\t(\"MemUsage\", \"%\")\n//\t(\"MemFree\", \"MB\")\n//\t(\"MemUsed\", \"MB\")\n//\t(\"DiskIO\", \"KB/s\")\n//\t(\"TPS\", \"TPS\")\n//\t(\"DiskTotal\", \"GB\")\n//\t(\"DiskUsed\", \"GB\")\n//\t(\"DiskFree\", \"GB\")\n//\t(\"DiskUsage\", \"%\")\n//\t(\"NoProcesses\", \"\")\n//\t(\"Load1\", \"\")\n//\t(\"Load5\", \"\")\n//\t(\"Load15\", \"\")\n//\t(\"In_\"+ifName, \"Mbps\")\n//\t(\"Out_\"+ifName, \"Mbps\")\n\n    private static final String SYS_EXTENDED_BIN_PATH = \"/bin,/sbin,/usr/bin,/usr/sbin,/usr/local/bin\";\n    static public String[] ResTypes;\n\n    static {\n        nf.setMaximumFractionDigits(4);\n        nf.setMinimumFractionDigits(4);\n    }\n\n    protected final Logger logger;\n    private final cmdExec exec;\n    private final LinkedList<String> devices = new LinkedList<String>();\n    private final HashMap<String, String> diskIOReadKB = new HashMap<String, String>();\n    private final HashMap<String, String> diskIOWriteKB = new HashMap<String, String>();\n    private final HashMap<String, String> dKBRead = new HashMap<String, String>();\n    private final HashMap<String, String> dKBWrite = new HashMap<String, String>();\n    private final Hashtable<String, String> netIn = new Hashtable<String, String>();\n    private final Hashtable<String, String> dnetIn = new Hashtable<String, String>();\n    private final Hashtable<String, String> netOut = new Hashtable<String, String>();\n    private final Hashtable<String, String> dnetOut = new Hashtable<String, String>();\n    protected String PROC_FILE_NAMES[];\n    protected FileReader fileReaders[];\n    protected BufferedReader bufferedReaders[];\n    String[] old; // = new long[8];\n    String[] cur;\n    String[] xtmp;\n    String[] diff;\n    long last_time_diskIO;\n    long last_time_cpu;\n    long last_time_net;\n    private boolean hasCommonCPUStats;\n    private boolean hasCPUIOWaitStats;\n    private boolean hasCPUIntStats;\n    private boolean hasCPUStealStats;\n    private boolean hasPageProcStat;\n    private boolean hasSwapProcStat;\n    private boolean hasPageProcVmStat;\n    private boolean hasSwapProcVmStat;\n    /**\n     * is this a 64 bits arch ?\n     */\n    private boolean is64BitArch = false;\n    private boolean alreadyInitCPU = false;\n    private String diskIO = null;\n    private String tps = null;\n    private double diskTotal;\n    private double diskUsed;\n    private double diskFree;\n    private double memUsage;\n    private double memUsed;\n    private double memFree;\n    private double load1, load5, load15;\n    private String[] netInterfaces = null;\n\n    public ProcReader(final Logger logger) {\n        this.logger = logger;\n        exec = cmdExec.getInstance();\n    }\n\n    public static void main(String args[]) {\n        ProcReader reader = new ProcReader(Logger.getLogger(\"lisa\"));\n        System.out.println(\"***\" + reader.getMACAddress());\n//\t\ttry {HashMap h = reader.getCPUVM();\n//\t\tSystem.out.println(h);} catch (Throwable t) { t.printStackTrace(); }\n//\t\ttry { Thread.sleep(1000); } catch (Throwable t) { }\n//\t\ttry {HashMap h = reader.getCPUVM();\n//\t\tSystem.out.println(h);} catch (Throwable t) { t.printStackTrace(); }\n//\t\ttry { Thread.sleep(1000); } catch (Throwable t) { }\n//\t\ttry {HashMap h = reader.getCPUVM();\n//\t\tSystem.out.println(h);} catch (Throwable t) { t.printStackTrace(); }\n        try {\n            HashMap h = reader.getNet();\n            System.out.println(h);\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n        try {\n            Thread.sleep(1000);\n        } catch (Throwable t) {\n        }\n        try {\n            HashMap h = reader.getNet();\n            System.out.println(h);\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n        try {\n            Thread.sleep(1000);\n        } catch (Throwable t) {\n        }\n    }\n\n    /**\n     * Method that returns the MAC hw address.\n     *\n     * @return The hw address or null\n     * @since java1.6\n     */\n    public final String getMACAddress() {\n        try {\n            Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();\n            while (en.hasMoreElements()) {\n                NetworkInterface ni = en.nextElement();\n                // get the hardware address\n                if (!ni.isLoopback()) {\n                    try {\n                        final String hadr = getHexa(ni.getHardwareAddress());\n                        if (hadr != null) return hadr;\n                    } catch (SocketException se) {\n                    } // nothing, just move on here\n                }\n                Enumeration<NetworkInterface> en1 = ni.getSubInterfaces();\n                while (en1.hasMoreElements()) {\n                    ni = en1.nextElement();\n                    // get the hardware address\n                    if (!ni.isLoopback()) {\n                        try {\n                            final String hadr = getHexa(ni.getHardwareAddress());\n                            if (hadr != null) return hadr;\n                        } catch (SocketException se) {\n                        } // nothing, just move on here\n                    }\n                }\n            }\n        } catch (Throwable se) {\n            logger.log(Level.INFO, \"Got error retrieving the network interfaces\", se);\n        }\n        // if we did not succeded in this way, then try using ifconfig instead.\n\n        final String path = getIfConfigPath();\n        CommandResult cmdRes = exec.executeCommandReality(\"ifconfig -a\", \"b\", path);\n        String output = cmdRes.getOutput();\n        if (cmdRes.failed())\n            output = null;\n        if (output != null && output.length() != 0 && !output.contains(\"No such file or directory\") && !output.contains(\"Segmentation fault\")) {\n            StringTokenizer st = new StringTokenizer(output);\n            String line = st.nextToken(\"\\n\");\n            while (line != null) {\n                if (line != null && (line.startsWith(\" \") || line.startsWith(\"\\t\"))) {\n                    line = st.nextToken(\"\\n\");\n                    continue;\n                }\n                if (line == null)\n                    break;\n                StringTokenizer ast = new StringTokenizer(line);\n                // get the name\n                ast.nextToken(\" \\t\\n\"); // netName\n                // get the hw address\n                if (line.indexOf(\"HWaddr \") >= 0) return line.substring(line.indexOf(\"HWaddr \") + 7);\n                line = st.nextToken(\"\\n\");\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Method to retrieve CPU related parameters..\n     *\n     * @return A hashmap<String, Double>, where String is the name of the param and Double is the current value\n     */\n    public final HashMap<String, Double> getCPUVM() throws Exception {\n        initCPUReaders();\n\n        if (cur == null)\n            cur = new String[ResTypes.length];\n        if (xtmp == null)\n            xtmp = new String[ResTypes.length];\n        if (diff == null)\n            diff = new String[ResTypes.length];\n\n\n        if (hasSwapProcVmStat || hasPageProcVmStat) {\n            PROC_FILE_NAMES = new String[]{\"/proc/stat\", \"/proc/vmstat\"};\n        } else if (hasCommonCPUStats || hasSwapProcStat || hasPageProcStat) {\n            PROC_FILE_NAMES = new String[]{\"/proc/stat\"};\n        } else\n            PROC_FILE_NAMES = null;\n        createReaders();\n\n        HashMap<String, Double> results = new HashMap<String, Double>();\n\n        long sTime = System.currentTimeMillis();\n        int len = ResTypes.length;\n        BufferedReader br = bufferedReaders[0];\n        int index = 0;\n        boolean parsedCPU = !hasCommonCPUStats;\n\n        for (; ; ) {\n            String lin = br.readLine();\n\n            if (lin == null)\n                break;\n\n            lin = lin.trim();\n            if (lin.length() == 0)\n                continue;\n\n            StringTokenizer tz = new StringTokenizer(lin);\n\n            String item = tz.nextToken().trim();\n            if (!parsedCPU && hasCommonCPUStats && item.equals(\"cpu\")) {\n                parsedCPU = true;\n                cur[index++] = tz.nextToken();\n                cur[index++] = tz.nextToken();\n                cur[index++] = tz.nextToken();\n                cur[index++] = tz.nextToken();\n\n                if (hasCPUIOWaitStats) {\n                    cur[index++] = tz.nextToken();\n                    if (hasCPUIntStats) {\n                        cur[index++] = tz.nextToken();\n                        cur[index++] = tz.nextToken();\n                        if (hasCPUStealStats) {\n                            cur[index++] = tz.nextToken();\n                        }\n                    }\n                }\n                if (hasPageProcVmStat && hasSwapProcVmStat)\n                    break;\n            } else if (item.equals(\"page\")) {\n                cur[index++] = tz.nextToken();\n                cur[index++] = tz.nextToken();\n            } else if (item.equals(\"swap\")) {\n                cur[index++] = tz.nextToken();\n                cur[index++] = tz.nextToken();\n            }\n        }\n\n        if (hasSwapProcVmStat || hasPageProcVmStat) {\n            br = bufferedReaders[1];\n            int cCount = 0;\n            String lin = br.readLine();\n            for (; cCount < 4 && lin != null; lin = br.readLine()) {\n                lin = lin.trim();\n                if (lin.startsWith(\"pgpgin\")) {\n                    cur[len - 4] = lin.substring(7);\n                    cCount++;\n                    continue;\n                }\n\n                if (lin.startsWith(\"pgpgout\")) {\n                    cur[len - 3] = lin.substring(8);\n                    cCount++;\n                    continue;\n                }\n\n                if (lin.startsWith(\"pswpin\")) {\n                    cur[len - 2] = lin.substring(7);\n                    cCount++;\n                    continue;\n                }\n\n                if (lin.startsWith(\"pswpout\")) {\n                    cur[len - 1] = lin.substring(8);\n                    cCount++;\n                    continue;\n                }\n            }\n        }\n        if (old == null) {\n            old = cur;\n            cur = xtmp;\n            last_time_cpu = System.currentTimeMillis();\n        } else {\n            for (int i = 0; i < diff.length; i++) {\n                diff[i] = diffWithOverflowCheck(cur[i], old[i]);\n            }\n\n            String sum = addWithOverflowCheck(diff[0], diff[1]);\n            sum = addWithOverflowCheck(sum, diff[2]);\n            sum = addWithOverflowCheck(sum, diff[3]);\n            if (hasCPUIOWaitStats) {\n                sum = addWithOverflowCheck(sum, diff[4]);\n                if (hasCPUIntStats) {\n                    sum = addWithOverflowCheck(sum, diff[5]);\n                    sum = addWithOverflowCheck(sum, diff[6]);\n                    if (hasCPUStealStats) {\n                        sum = addWithOverflowCheck(sum, diff[7]);\n                    }\n                }\n            }\n            index = 0;\n\n            String str1 = divideWithOverflowCheck(diff[0], sum);\n            double d = Double.parseDouble(str1) * 100D;\n            double totalP = d;\n            results.put(ResTypes[index++], d);\n            str1 = divideWithOverflowCheck(diff[1], sum);\n            d = Double.parseDouble(str1) * 100D;\n            totalP += d;\n            results.put(ResTypes[index++], d);\n            str1 = divideWithOverflowCheck(diff[2], sum);\n            d = Double.parseDouble(str1) * 100D;\n            totalP += d;\n            results.put(ResTypes[index++], d);\n\n            if (hasCPUIOWaitStats) {\n                str1 = divideWithOverflowCheck(diff[4], sum);\n                d = Double.parseDouble(str1) * 100D;\n                totalP += d;\n                results.put(ResTypes[index++], d);\n                if (hasCPUIntStats) {\n                    str1 = divideWithOverflowCheck(diff[5], sum);\n                    d = Double.parseDouble(str1) * 100D;\n                    totalP += d;\n                    results.put(ResTypes[index++], d);\n                    str1 = divideWithOverflowCheck(diff[6], sum);\n                    d = Double.parseDouble(str1) * 100D;\n                    totalP += d;\n                    results.put(ResTypes[index++], d);\n                    if (hasCPUStealStats) {\n                        str1 = divideWithOverflowCheck(diff[7], sum);\n                        d = Double.parseDouble(str1) * 100D;\n                        totalP += d;\n                        results.put(ResTypes[index++], d);\n                    }\n                }\n            }\n\n            str1 = divideWithOverflowCheck(diff[3], sum);\n            d = Double.parseDouble(str1) * 100D;\n            results.put(ResTypes[index++], d);\n            if (Math.abs(totalP + d - 0D) < 0.0001)\n                results.put(\"CPU_Usage\", 1.0);\n            else\n                results.put(\"CPU_usage\", (totalP / (totalP + d)));\n            double imp = ((sTime - last_time_cpu) / 1000D) * 1024D;\n\n\t\t\t/*\n             * Little comment here ( hopefully both page|swap _in|out will be in MB/s Check this first: - http://lkml.org/lkml/2002/4/12/6 -\n\t\t\t * http://marc.theaimsgroup.com/?l=linux-kernel&m=101770318012189&w=2 the page_[ in | out ] represents in 1KB values the swap_[ in | out ] represents in PAGE_SIZE,\n\t\t\t * usually 4KB values\n\t\t\t */\n            results.put(ResTypes[len - 4], Double.valueOf(divideWithOverflowCheck(diff[len - 4], \"\" + imp)));\n            results.put(ResTypes[len - 3], Double.valueOf(divideWithOverflowCheck(diff[len - 3], \"\" + imp)));\n\n            // TODO - this can be buggy\n\t\t\t/*\n\t\t\t * To termine the PAGE_SIZE you can run this code cat << EOF | #include <stdio.h> main() { printf (\"%d bytes\\n\",getpagesize()); } EOF gcc -xc - -o /tmp/getpagesize\n\t\t\t * /tmp/getpagesize; rm -f /tmp/getpagesize PAGE_SIZE was 4096 bytes on all these machines ( though on SunOS the module does not work ! ): Linux pccit16 2.6.17-rc2 #2\n\t\t\t * SMP Wed Apr 19 10:25:58 CEST 2006 i686 pentium4 i386 GNU/Linux ( Slack_10.2 ) Linux pccit15 2.4.20-18.7.cernsmp #1 SMP Thu Jun 12 12:27:49 CEST 2003 i686 unknown (\n\t\t\t * RH_7.3 ) Linux lxplus056.cern.ch 2.4.21-40.EL.cernsmp #1 SMP Fri Mar 17 00:53:42 CET 2006 i686 i686 i386 GNU/Linux ( SLC 3.0.6 ) SunOS vinci 5.10 Generic_118844-26\n\t\t\t * i86pc i386 i86pc Linux pccil 2.6.5-7.252-smp #1 SMP Tue Feb 14 11:11:04 UTC 2006 i686 i686 i386 GNU/Linux ( SuSE Linux 9.1 )\n\t\t\t */\n            results.put(ResTypes[len - 2], Double.valueOf(divideWithOverflowCheck((mulWithOverflowCheck(diff[len - 2], \"\" + 4)), \"\" + imp)));\n            results.put(ResTypes[len - 1], Double.valueOf(divideWithOverflowCheck((mulWithOverflowCheck(diff[len - 1], \"\" + 4)), \"\" + imp)));\n\n            last_time_cpu = sTime;\n            xtmp = old;\n            old = cur;\n            cur = xtmp;\n        }\n\n        cleanup();\n        return results;\n    }\n\n    /**\n     * Method to retrieve memory information\n     *\n     * @return Mapping <String, Double> if the memory related params\n     */\n    public HashMap<String, Double> getMEM() throws Exception {\n\n        BufferedReader in = new BufferedReader(new FileReader(\"/proc/meminfo\"));\n        String line = in.readLine();\n        String sMemFree, sMemTotal;\n        HashMap<String, Double> results = new HashMap<String, Double>();\n        double dmemTotal = 0.0, dmemFree = 0.0;\n        while (line != null) {\n            if (line.startsWith(\"MemTotal:\")) {\n                line = line.substring(9);\n                StringTokenizer ast = new StringTokenizer(line);\n                try {\n                    sMemTotal = ast.nextToken();\n                } catch (Exception e) {\n                    sMemTotal = null;\n                }\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(sMemTotal);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0)\n                    dmemTotal = d;\n            }\n            if (line.startsWith(\"MemFree:\")) {\n                line = line.substring(8);\n                StringTokenizer ast = new StringTokenizer(line);\n                try {\n                    sMemFree = ast.nextToken();\n                } catch (Exception e) {\n                    sMemFree = null;\n                }\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(sMemFree);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d >= 0.0)\n                    dmemFree = d;\n            }\n            line = in.readLine();\n        }\n        memFree = (dmemFree / 1024.0);\n        memUsed = ((dmemTotal - dmemFree) / 1024.0);\n        memUsage = (100.0 * (dmemTotal - dmemFree) / dmemTotal);\n        results.put(\"MemUsage\", memUsage);\n        results.put(\"MemUsed\", memUsed);\n        results.put(\"MemFree\", memFree);\n        in.close();\n        return results;\n    }\n\n    /**\n     * Method to retrieve information related to disk usage..\n     *\n     * @return Mapping <String, Double> of disk params...\n     */\n    public HashMap<String, Double> getDISK() throws Exception {\n        String output = executeIOStat();\n        String line, str;\n        if (output != null && !output.equals(\"\")) {\n            long now = System.currentTimeMillis();\n            diskIO = \"0.00\";\n            tps = \"0.00\";\n            StringTokenizer st = new StringTokenizer(output);\n            try {\n                line = st.nextToken(\"\\n\");\n            } catch (Exception e) {\n                line = null;\n            }\n            double imp = ((now - last_time_diskIO) / 1000D) * 1024D;\n            while (line != null && !line.contains(\"Device:\")) {\n                try {\n                    line = st.nextToken(\"\\n\");\n                } catch (Exception e) {\n                    line = null;\n                }\n            }\n            devices.clear();\n            if (line != null) {\n                String diff1 = null, diff2 = null;\n                while (true) {\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    }\n                    if (str == null)\n                        break;\n                    final String device = str;\n                    devices.addLast(device);\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    } // tps\n                    tps = addWithOverflowCheck(str, tps);\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    } // skip KB read / sec\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    } // skip KB write / sec\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    } // KB read\n                    final String dKBr = (String) dKBRead.get(device);\n                    diff1 = diffWithOverflowCheck(str, dKBr == null ? str : dKBr);\n                    diskIO = addWithOverflowCheck(diff1, diskIO);\n                    if (dKBRead.containsKey(device)) {\n                        String s = diffWithOverflowCheck(str, dKBr);\n                        diskIOReadKB.put(device, divideWithOverflowCheck(s, \"\" + imp));\n                    }\n                    dKBRead.put(device, str);\n                    // sec\n                    try {\n                        str = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        str = null;\n                    } // skip KB write /\n                    final String dKBw = (String) dKBWrite.get(device);\n                    diff2 = diffWithOverflowCheck(str, dKBw == null ? str : dKBw);\n                    diskIO = addWithOverflowCheck(diff2, diskIO);\n                    if (dKBWrite.containsKey(device)) {\n                        String s = diffWithOverflowCheck(str, dKBw);\n                        diskIOWriteKB.put(device, divideWithOverflowCheck(s, \"\" + imp));\n                    }\n                    dKBWrite.put(device, str);\n                }\n            }\n\n            diskIO = divideWithOverflowCheck(diskIO, \"\" + imp);\n            last_time_diskIO = now;\n        } else return null;\n\n        HashMap<String, Double> results = new HashMap<String, Double>();\n\n        LinkedList<String> toRemove = new LinkedList<String>();\n        for (Iterator<String> it = dKBRead.keySet().iterator(); it.hasNext(); ) {\n            String d = it.next();\n            if (!devices.contains(d)) {\n                toRemove.addLast(d);\n            }\n        }\n        for (Iterator<String> it = toRemove.iterator(); it.hasNext(); ) {\n            String d = it.next();\n            dKBRead.remove(d);\n            dKBWrite.remove(d);\n            diskIOReadKB.remove(d);\n            diskIOWriteKB.remove(d);\n        }\n\n        output = executeDF();\n        double size = 0.0, used = 0.0, available = 0.0, usage = 0.0;\n        if (output != null && output != \"\") {\n            StringTokenizer st = new StringTokenizer(output);\n            try {\n                line = st.nextToken(\" \\t\\n\");\n            } catch (Exception e) {\n                line = null;\n            }\n            int nr = 0;\n            for (int i = 0; i < 6 && line != null; i++)\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                }\n            while (true) {\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                }\n                if (line == null)\n                    break;\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                } // size\n                double d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0)\n                    break;\n                size += d;\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                } // used\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0)\n                    break;\n                used += d;\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                } // available\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0)\n                    break;\n                available += d;\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                } // usage\n                try {\n                    line = line.substring(0, line.indexOf(\"%\"));\n                } catch (Exception e) {\n                }\n                d = 0.0;\n                try {\n                    d = Double.parseDouble(line);\n                } catch (Exception e) {\n                    d = -1.0;\n                }\n                if (d < 0.0)\n                    break;\n                usage += d;\n                nr++;\n                try {\n                    line = st.nextToken(\" \\t\\n\");\n                } catch (Exception e) {\n                    line = null;\n                }\n                if (line == null)\n                    break;\n            }\n            diskTotal = (size / (1024.0 * 1024.0)); // total size (GB)\n            diskUsed = (used / (1024.0 * 1024.0)); // used size (GB)\n            diskFree = (available / (1024.0 * 1024.0)); // free size\n            // (GB)\n//\t\t\tdiskUsage = (usage * 1.0 / nr); // usage (%)\n        } else { // read from /proc/ide\n            String files[] = listFiles(\"/proc/ide\");\n            if (files != null && files.length != 0)\n                for (int i = 0; i < files.length; i++)\n                    if (files[i].startsWith(\"hd\")) {\n                        try {\n                            BufferedReader in = new BufferedReader(new FileReader(\"/proc/ide/\" + files[i] + \"/capacity\"));\n                            line = in.readLine();\n                            double d = 0.0;\n                            try {\n                                d = Double.parseDouble(line);\n                            } catch (Exception e) {\n                                d = -1.0;\n                            }\n                            if (d >= 0.0)\n                                size += d;\n                            in.close();\n                        } catch (Exception e) {\n                        }\n                    }\n            diskTotal = (size / (1024.0 * 1024.0)); // disk total (GB)\n            diskFree = diskTotal;\n        }\n\n        try {\n            results.put(\"DiskIO\", Double.valueOf(diskIO));\n        } catch (Exception e) {\n            results.put(\"DiskIO\", -1.0);\n        }\n        try {\n            results.put(\"TPS\", Double.valueOf(tps));\n        } catch (Exception e) {\n            results.put(\"TPS\", -1.0);\n        }\n        if (devices != null)\n            for (String dev : devices) {\n                if (diskIOReadKB.containsKey(dev)) {\n                    try {\n                        results.put(\"DiskIORead_\" + dev, Double.valueOf(diskIOReadKB.get(dev)));\n                    } catch (Exception e) {\n                        results.put(\"DiskIORead_\" + dev, -1.0);\n                    }\n                }\n                if (diskIOWriteKB.containsKey(dev)) {\n                    try {\n                        results.put(\"DiskIORead_\" + dev, Double.valueOf(diskIOReadKB.get(dev)));\n                    } catch (Exception e) {\n                        results.put(\"DiskIORead_\" + dev, -1.0);\n                    }\n                }\n            }\n        results.put(\"DiskTotal\", diskTotal);\n        results.put(\"DiskUsed\", diskUsed);\n        results.put(\"DiskFree\", diskFree);\n        results.put(\"DiskUsage\", new Double(100.0 * diskUsed / (diskUsed + diskFree)));\n        toRemove.clear();\n        return results;\n    }\n\n    /**\n     * Retrieves the number of running processes or -1 if error\n     *\n     * @return The number of processes\n     */\n    public int getProcesses() {\n        String[] files = listFiles(\"/proc\");\n        if (files != null && files.length != 0) {\n            int nr = 0;\n            for (int i = 0; i < files.length; i++) {\n                char[] chars = files[i].toCharArray();\n                boolean isProc = true;\n                for (int j = 0; j < chars.length; j++)\n                    if (!Character.isDigit(chars[j])) {\n                        isProc = false;\n                        break;\n                    }\n                if (isProc)\n                    nr++;\n            }\n            return nr;\n        }\n        return -1;\n    }\n\n    /**\n     * Retrieves the current load values\n     *\n     * @return Mapping <String, Double> of load1, 5, 15\n     */\n    public HashMap<String, Double> getLOAD() throws Exception {\n        BufferedReader in = new BufferedReader(new FileReader(\"/proc/loadavg\"));\n        String f = \"\";\n        String line;\n        while ((line = in.readLine()) != null) {\n            f = f + \"\\n\" + line;\n        }\n        in.close();\n        HashMap<String, Double> results = new HashMap<String, Double>();\n        StringTokenizer st = new StringTokenizer(f);\n        try {\n            line = st.nextToken(\" \\t\\n\");\n        } catch (Exception e) {\n            line = null;\n        } // load1\n        if (line != null) {\n            double d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0)\n                load1 = d;\n            try {\n                line = st.nextToken(\" \\t\\n\");\n            } catch (Exception e) {\n                line = null;\n            }// load5\n            d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0)\n                load5 = d;\n            try {\n                line = st.nextToken(\" \\t\\n\");\n            } catch (Exception e) {\n                line = null;\n            } // load15\n            d = 0.0;\n            try {\n                d = Double.parseDouble(line);\n            } catch (Exception e) {\n                d = -1.0;\n            }\n            if (d >= 0.0)\n                load15 = d;\n        }\n        results.put(\"Load1\", load1);\n        results.put(\"Load5\", load5);\n        results.put(\"Load15\", load15);\n        return results;\n    }\n\n    /**\n     * Method to retrieve traffic information\n     *\n     * @return Mapping <String, Double> of in and out traffic for each found interfaces\n     */\n    public HashMap<String, Double> getNet() throws Exception {\n        String line;\n        BufferedReader in = new BufferedReader(new FileReader(\"/proc/net/dev\"));\n        String f = \"\";\n        while ((line = in.readLine()) != null) {\n            f = f + \"\\n\" + line;\n        }\n        in.close();\n        HashMap<String, Double> results = new HashMap<String, Double>();\n        StringTokenizer st = new StringTokenizer(f);\n        long now = System.currentTimeMillis();\n        if (netInterfaces == null) {\n            while (true) {\n                try {\n                    line = st.nextToken(\":\\n\\t \");\n                } catch (Exception e) {\n                    line = null;\n                }\n                if (line == null)\n                    break;\n                if (line.startsWith(\"eth\") || line.startsWith(\"lo\")) {\n                    addNetInterface(line);\n                    String name = line;\n                    try {\n                        line = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        line = null;\n                    } // bytes received\n                    if (dnetIn.containsKey(name)) {\n                        final String lastIn = dnetIn.get(name);\n                        try {\n                            double d = Double.parseDouble(diffWithOverflowCheck(line, lastIn));\n                            d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                            netIn.put(name, \"\" + d);\n                        } catch (Exception e) {\n                        }\n                        dnetIn.put(name, line);\n                    } else {\n                        netIn.put(name, line);\n                        dnetIn.put(name, line);\n                    }\n                    for (int i = 0; i < 7; i++) {\n                        try {\n                            line = st.nextToken(\" \\t\\n\");\n                        } catch (Exception e) {\n                            line = null;\n                        }\n                    }\n                    try {\n                        line = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        line = null;\n                    } // bytes sent\n                    if (dnetOut.containsKey(name)) {\n                        final String lastOut = dnetOut.get(name);\n                        try {\n                            double d = Double.parseDouble(diffWithOverflowCheck(line, lastOut));\n                            d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                            netOut.put(name, \"\" + d);\n                        } catch (Exception e) {\n                        }\n                        dnetOut.put(name, line);\n                    } else {\n                        netOut.put(name, line);\n                        dnetOut.put(name, line);\n                    }\n                }\n            }\n        } else {\n            while (true) {\n                try {\n                    line = st.nextToken(\":\\n\\t \");\n                } catch (Exception e) {\n                    line = null;\n                }\n                if (line == null)\n                    break;\n                boolean found = false;\n                for (int i = 0; i < netInterfaces.length; i++)\n                    if (line.equals(netInterfaces[i])) {\n                        found = true;\n                        break;\n                    }\n                if (found) {\n                    String name = line;\n                    try {\n                        line = st.nextToken(\" \\t\\n:\");\n                    } catch (Exception e) {\n                        line = null;\n                    }// bytes received\n                    if (dnetIn.containsKey(name)) {\n                        final String lastIn = dnetIn.get(name);\n                        try {\n                            double d = Double.parseDouble(diffWithOverflowCheck(line, lastIn));\n                            d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                            // logger.info(\"For \"+name+\"in = \"+d+\" old=\"+lastIn+\" new=\"+line+\" diff=\"+(now - last_time_net));\n                            netIn.put(name, \"\" + d);\n                        } catch (Exception e) {\n                        }\n                        dnetIn.put(name, line);\n                    } else {\n                        netIn.put(name, line);\n                        dnetIn.put(name, line);\n                    }\n                    for (int i = 0; i < 7; i++) {\n                        try {\n                            line = st.nextToken(\" \\t\\n\");\n                        } catch (Exception e) {\n                            line = null;\n                        }\n                    }\n                    try {\n                        line = st.nextToken(\" \\t\\n\");\n                    } catch (Exception e) {\n                        line = null;\n                    } // bytes sent\n                    if (dnetOut.containsKey(name)) {\n                        final String lastOut = dnetOut.get(name);\n                        try {\n                            double d = Double.parseDouble(diffWithOverflowCheck(line, lastOut));\n                            d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                            // logger.info(\"For \"+name+\" out = \"+d+\" old=\"+lastOut+\" new=\"+line+\" diff=\"+(now - last_time_net));\n                            netOut.put(name, \"\" + d);\n                        } catch (Exception e) {\n                        }\n                        dnetOut.put(name, line);\n                    } else {\n                        netOut.put(name, line);\n                        dnetOut.put(name, line);\n                    }\n                } else {\n                    if (line.startsWith(\"eth\") || line.startsWith(\"lo\")) {\n                        addNetInterface(line);\n                        String name = line;\n                        try {\n                            line = st.nextToken(\" \\t\\n\");\n                        } catch (Exception e) {\n                            line = null;\n                        } // bytes received\n                        if (dnetIn.containsKey(name)) {\n                            final String lastIn = dnetIn.get(name);\n                            try {\n                                double d = Double.parseDouble(diffWithOverflowCheck(line, lastIn));\n                                d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                                netIn.put(name, \"\" + d);\n                            } catch (Exception e) {\n                            }\n                            dnetIn.put(name, line);\n                        } else {\n                            netIn.put(name, line);\n                            dnetIn.put(name, line);\n                        }\n                        for (int i = 0; i < 7; i++) {\n                            try {\n                                line = st.nextToken(\" \\t\\n\");\n                            } catch (Exception e) {\n                                line = null;\n                            }\n                        }\n                        try {\n                            line = st.nextToken(\" \\t\\n\");\n                        } catch (Exception e) {\n                            line = null;\n                        } // bytes sent\n                        if (dnetOut.containsKey(name)) {\n                            final String lastOut = dnetOut.get(name);\n                            try {\n                                double d = Double.parseDouble(diffWithOverflowCheck(line, lastOut));\n                                d = (d * 8.0D) / (now - last_time_net) / 1000.0D;\n                                netOut.put(name, \"\" + d);\n                            } catch (Exception e) {\n                            }\n                            dnetOut.put(name, line);\n                        } else {\n                            netOut.put(name, line);\n                            dnetOut.put(name, line);\n                        }\n                    }\n                }\n            }\n        }\n        last_time_net = now;\n        if (netInterfaces != null && netInterfaces.length != 0)\n            for (int i = 0; i < netInterfaces.length; i++) {\n                final String ifName = netInterfaces[i];\n                try {\n                    results.put(\"In_\" + ifName, Double.valueOf(netIn.get(ifName)));\n                } catch (Exception e) {\n                }\n                try {\n                    results.put(\"Out_\" + ifName, Double.valueOf(netOut.get(ifName)));\n                } catch (Exception e) {\n                }\n            }\n        return results;\n    }\n\n    /**\n     * UTILITY METHODS\n     */\n\n    private final String getHexa(byte[] b) {\n        if (b == null || b.length == 0) return null;\n        StringBuffer buf = new StringBuffer();\n        for (int i = 0; i < b.length; i++) {\n            byte value = b[i];\n            int d1 = value & 0xF;\n            d1 += (d1 < 10) ? 48 : 55;\n            int d2 = (value & 0xF0) >> 4;\n            d2 += (d2 < 10) ? 48 : 55;\n            buf.append((char) d2).append((char) d1);\n            if (i < b.length - 1) buf.append(':');\n        }\n        return buf.toString();\n    }\n\n    private final synchronized String getIfConfigPath() {\n        String path = SYS_EXTENDED_BIN_PATH;\n        if (System.getProperty(\"ifconfig.path\", null) != null)\n            path = System.getProperty(\"ifconfig.path\");\n        if (path == null || path.length() == 0) {\n            logger.warning(\"[Host - ifconfig can not be found in \" + path + \"]\");\n            return null;\n        }\n        return path.replace(',', ':').trim();\n    }\n\n    private final void initCPUReaders() {\n        if (alreadyInitCPU) return;\n        try {\n            ArrayList<String> al = new ArrayList<String>(15);// at least\n            // 12\n            FileReader fr = null;\n            BufferedReader br = null;\n            File procFile = null;\n            // check for info that can be processed from /proc/stat\n            try {\n                procFile = new File(\"/proc/stat\");\n                if (procFile.exists() && procFile.canRead()) {\n                    fr = new FileReader(\"/proc/stat\");\n                    br = new BufferedReader(fr);\n                    String line = br.readLine();\n                    boolean parsedCPU = false;\n                    for (; line != null; line = br.readLine()) {\n                        line = line.trim();\n                        if (!parsedCPU && line.startsWith(\"cpu\")) {\n                            parsedCPU = true;\n                            String[] tokens = line.split(\"(\\\\s)+\");\n                            int len = tokens.length;\n                            if (len >= 5) {\n                                al.add(\"CPU_usr\");\n                                al.add(\"CPU_nice\");\n                                al.add(\"CPU_sys\");\n                                hasCommonCPUStats = true;\n                                if (len >= 6) {\n                                    al.add(\"CPU_iowait\");\n                                    hasCPUIOWaitStats = true;\n                                    if (len >= 8) {\n                                        al.add(\"CPU_int\");\n                                        al.add(\"CPU_softint\");\n                                        hasCPUIntStats = true;\n                                        if (len >= 9) {\n                                            al.add(\"CPU_steal\");\n                                            hasCPUStealStats = true;\n                                        }\n                                    }\n                                }\n                                al.add(\"CPU_idle\");\n                            }// if (len >= 5 )\n                        } else {// if ( \"cpu\" )\n                            if (line.startsWith(\"page\")) {\n                                hasPageProcStat = true;\n                            } else if (line.startsWith(\"swap\")) {\n                                hasSwapProcStat = true;\n                            }\n                        }\n                    }// for\n                }// if ( procStatF.exists() )\n            } catch (Throwable pft) {\n                logger.log(Level.WARNING, \"Checking for /proc/stat yield a caught exception \", pft);\n            } finally {\n                try {\n                    if (fr != null)\n                        fr.close();\n                    if (br != null)\n                        br.close();\n                } catch (Throwable ignore) {\n                }\n                fr = null;\n                br = null;\n            }\n\n            // check for info that can be processed from /proc/vmstat\n            procFile = new File(\"/proc/vmstat\");\n            try {\n                if (procFile.exists() && procFile.canRead()) {\n                    fr = new FileReader(\"/proc/vmstat\");\n                    br = new BufferedReader(fr);\n\n                    String line = br.readLine();\n                    for (; line != null; line = br.readLine()) {\n                        line = line.trim();\n                        if (line.startsWith(\"pgpgin\")) {\n                            hasPageProcVmStat = true;\n                            continue;\n                        }\n                        if (line.startsWith(\"pswpin\")) {\n                            hasSwapProcVmStat = true;\n                            continue;\n                        }\n                    }// for\n                }// if - exists && canRead\n            } catch (Throwable pft) {\n                logger.log(Level.WARNING, \"Checking for /proc/vmstat yield a caught exception \", pft);\n            } finally {\n                try {\n                    if (fr != null)\n                        fr.close();\n                    if (br != null)\n                        br.close();\n                } catch (Throwable ignore) {\n                }\n                fr = null;\n                br = null;\n            }\n\n            if (hasPageProcStat || hasPageProcVmStat) {\n                al.add(\"Page_in\");\n                al.add(\"Page_out\");\n            }\n\n            if (hasSwapProcStat || hasSwapProcVmStat) {\n                al.add(\"Swap_in\");\n                al.add(\"Swap_out\");\n            }\n            ResTypes = (String[]) al.toArray(new String[al.size()]);\n            alreadyInitCPU = true;\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception in init. The module will not be used for local monitoring \", t);\n        }\n    }\n\n    protected void resetReaders() throws Exception {\n        createReaders();\n    }\n\n    public void cleanup() {\n        if (bufferedReaders != null) {\n            for (int i = 0; i < bufferedReaders.length; i++) {\n                try {\n                    if (bufferedReaders[i] != null) {\n                        bufferedReaders[i].close();\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Got exception closing buffered reader [ \" + i + \" ] \", t);\n                } finally {\n                    bufferedReaders[i] = null; // let GC do the job\n                }\n            }\n        }// if bufferedReaders\n        if (fileReaders != null) {\n            for (int i = 0; i < fileReaders.length; i++) {\n                try {\n                    if (fileReaders[i] != null) {\n                        fileReaders[i].close();\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Got exception closing file reader [ \" + i + \" ] \", t);\n                } finally {\n                    fileReaders[i] = null; // let GC do the job\n                }\n            }\n        }\n    }\n\n    private void createReaders() throws Exception {\n        cleanup();\n        if (PROC_FILE_NAMES == null)\n            throw new Exception(\" PROC_FILE_NAMES is null\");\n\n        if (bufferedReaders == null || bufferedReaders.length != PROC_FILE_NAMES.length) {\n            bufferedReaders = new BufferedReader[PROC_FILE_NAMES.length];\n        }\n\n        if (fileReaders == null || fileReaders.length != PROC_FILE_NAMES.length) {\n            fileReaders = new FileReader[PROC_FILE_NAMES.length];\n        }\n\n        for (int i = 0; i < PROC_FILE_NAMES.length; i++) {\n            try {\n                if (PROC_FILE_NAMES[i] != null) {\n                    fileReaders[i] = new FileReader(PROC_FILE_NAMES[i]);\n                    bufferedReaders[i] = new BufferedReader(fileReaders[i]);\n                } else {\n                    logger.warning(\"PROC_FILE_NAMES[\" + i + \"] is null\");\n                }\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exc creating Readers [ \" + i + \" ] :- \" + PROC_FILE_NAMES[i] + \" \", t);\n            }\n        }\n    }\n\n    private String addWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n\n        if (newVal == null)\n            return oldVal;\n        if (oldVal == null)\n            return newVal;\n\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.add(oldv).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return addWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        return \"\" + (newv + oldv);\n    }\n\n    private String divideWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.divide(oldv, BigDecimal.ROUND_FLOOR).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return divideWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        return \"\" + (newv / oldv);\n    }\n\n    private String mulWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.multiply(oldv).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return mulWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        return \"\" + (newv * oldv);\n    }\n\n    private String diffWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            if (newv.compareTo(oldv) >= 0)\n                return newv.subtract(oldv).toString();\n            BigInteger overflow = new BigInteger(\"1\").shiftLeft(64);\n            BigDecimal d = new BigDecimal(overflow.toString());\n            return newv.add(d).subtract(oldv).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return diffWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        if (newv >= oldv) {\n            return \"\" + (newv - oldv);\n        }\n        long vmax = 1L << 32; // 32 bits\n        return \"\" + (newv - oldv + vmax);\n    }\n\n    private final String prepareString(String str) {\n\n        // first try to make it double\n        try {\n            double d = Double.parseDouble(str);\n            if (!Double.isInfinite(d) && !Double.isNaN(d)) {\n                String n = nf.format(d);\n                n = n.replaceAll(\",\", \"\");\n                return n;\n            }\n        } catch (Throwable t) {\n        }\n\n        if (!str.contains(\".\")) {\n            return str + \".0000\";\n        }\n        int nr = str.lastIndexOf('.') + 1;\n        nr = str.length() - nr;\n        for (int i = nr; i < 4; i++)\n            str += \"0\";\n        return str;\n    }\n\n    private final synchronized String executeIOStat() {\n\n        String path = SYS_EXTENDED_BIN_PATH + \",\" + System.getProperty(\"user.home\");\n        if (System.getProperty(\"iostat.path\", null) != null)\n            path = System.getProperty(\"iostat.path\");\n        if (path != null && path.length() != 0) {\n            path = path.replace(',', ':').trim();\n        }\n\n        CommandResult cmdRes = exec.executeCommandReality(\"iostat -k\", \"L\", path);\n        final String output = cmdRes.getOutput();\n        if (!cmdRes.failed() && output.length() != 0 && !output.contains(\"No such file or directory\") && !output.contains(\"Segmentation fault\"))\n            return output;\n        return null;\n    }\n\n    private final synchronized String executeDF() {\n\n        String path = SYS_EXTENDED_BIN_PATH;\n        if (System.getProperty(\"df.path\", null) != null)\n            path = System.getProperty(\"df.path\");\n        if (path != null && path.length() != 0) {\n            path = path.replace(\",\", \":\").trim();\n        }\n        CommandResult cmdRes = exec.executeCommandReality(\"df -B 1024\", \"o\", path);\n        String output = cmdRes.getOutput();\n        if (!cmdRes.failed() && output.length() != 0 && !output.contains(\"No such file or directory\") && !output.contains(\"Segmentation fault\"))\n            return output;\n        return null;\n    }\n\n    private String[] listFiles(String directory) {\n        String[] fileList = null;\n        try {\n            File dir = new File(directory);\n            if (!dir.isDirectory()) return null;\n            File[] list = dir.listFiles();\n            if (list == null) return null;\n            fileList = new String[list.length];\n            for (int i = 0; i < list.length; i++)\n                fileList[i] = list[i].getName();\n        } catch (Exception e) {\n            return null;\n        }\n        return fileList;\n    }\n\n    private void addNetInterface(String netInterface) {\n        if (netInterface == null || netInterface.equals(\"\"))\n            return;\n        netInterface = netInterface.trim();\n        if (netInterfaces == null) {\n            netInterfaces = new String[1];\n            netInterfaces[0] = netInterface;\n            return;\n        }\n        for (int i = 0; i < netInterfaces.length; i++)\n            if (netInterface.equals(netInterfaces[i]))\n                return;\n        String[] tmpNetInterfaces = new String[netInterfaces.length + 1];\n        System.arraycopy(netInterfaces, 0, tmpNetInterfaces, 0, netInterfaces.length);\n        tmpNetInterfaces[netInterfaces.length] = netInterface;\n        netInterfaces = tmpNetInterfaces;\n    }\n\n} // end of class ProcReader\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/cmdExec.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.LinkedList;\nimport java.util.logging.Logger;\nimport java.util.regex.Pattern;\n\n/**\n * This class was taken more or less from MonALISA\n *\n * @author Ciprian Dobre\n * @author ramiro\n */\n\n// FIXME - UPDATE!!! this class with latest version from ML!!! \npublic class cmdExec {\n\n    /**\n     * structure for command output\n     */\n    public static CommandResult NullCommandResult = new CommandResult(null, true);\n    private static cmdExec _instance = null;\n    public final transient Logger logger = Logger.getLogger(\"monalisa.util.cmdExec\");\n    public String full_cmd;\n    public Process pro;\n    protected LinkedList streams = null;\n    protected LinkedList streamsReal = null;\n\n    //protected boolean isError = false;\n\n    /* These varibles are set to true when we want to destroy the streams pool */\n    protected boolean stopStreams = false;\n    protected boolean stopStreamsReal = false;\n    String osname;\n    String exehome = \"\";\n\n    private cmdExec() {\n        osname = System.getProperty(\"os.name\");\n        exehome = System.getProperty(\"user.home\");\n        streams = new LinkedList();\n        streamsReal = new LinkedList();\n    }\n\n    public static synchronized cmdExec getInstance() {\n        if (_instance == null)\n            _instance = new cmdExec();\n        return _instance;\n    }\n\n    public void setCmd(String cmd) {\n        osname = System.getProperty(\"os.name\");\n        full_cmd = cmd; // local\n    }\n\n    public BufferedReader procOutput(String cmd) {\n        try {\n\n            if (osname.startsWith(\"Linux\") || osname.startsWith(\"Mac\")) {\n                pro =\n                        Runtime.getRuntime().exec(\n                                new String[]{\"/bin/sh\", \"-c\", cmd});\n            } else if (osname.startsWith(\"Windows\")) {\n                pro = Runtime.getRuntime().exec(exehome + cmd);\n            }\n\n            InputStream out = pro.getInputStream();\n            BufferedReader br = new BufferedReader(new InputStreamReader(out));\n            BufferedReader err = new BufferedReader(new InputStreamReader(pro.getErrorStream()));\n\n            String buffer = \"\";\n            String ret = \"\";\n            while ((buffer = err.readLine()) != null) {\n                ret += buffer + \"\\n'\";\n            }\n\n            if (ret.length() != 0) {\n                return null;\n            }\n\n            return br;\n\n        } catch (Exception e) {\n            logger.warning(\"FAILED to execute cmd = \" + exehome + cmd);\n            Thread.currentThread().interrupt();\n        }\n\n        return null;\n    }\n\n    public BufferedReader exeHomeOutput(String cmd) {\n\n        try {\n            pro =\n                    Runtime.getRuntime().exec(\n                            new String[]{\"/bin/sh\", \"-c\", exehome + cmd});\n            InputStream out = pro.getInputStream();\n            BufferedReader br = new BufferedReader(new InputStreamReader(out));\n\n            BufferedReader err = new BufferedReader(new InputStreamReader(pro.getErrorStream()));\n\n            String buffer = \"\";\n            String ret = \"\";\n            while ((buffer = err.readLine()) != null) {\n                ret += buffer + \"\\n'\";\n            }\n\n            if (ret.length() != 0) {\n                return null;\n            }\n            return br;\n        } catch (Exception e) {\n            logger.warning(\"FAILED to execute cmd = \" + exehome + cmd);\n            Thread.currentThread().interrupt();\n        }\n        return null;\n    }\n\n    public void stopModule() {\n        if (this.pro != null)\n            this.pro.destroy();\n    }\n\n    public BufferedReader readProc(String filePath) {\n        try {\n            return new BufferedReader(new FileReader(filePath));\n        } catch (Exception e) {\n\n            return null;\n        }\n    }\n\n    public CommandResult executeCommand(String command, String expect) {\n        return executeCommand(command, expect, 60 * 1000);\n    }\n\n    public CommandResult executeCommand(String command, String expect, long timeout) {\n\n        StreamGobbler output = null;\n        StreamGobbler error = null;\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1 || osName.indexOf(\"Mac\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamGobbler();\n            output = getStreamGobbler();\n\n            // any error message?\n            error.setInputStream(proc.getErrorStream());\n\n            // any output?\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            // any error???\n            long startTime = System.currentTimeMillis();\n            while (true) {\n                try {\n                    out = error.getOutput();\n                    if (out != null && out.length() != 0 && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.getOutput();\n                    if (out != null && out.length() != 0 && out.indexOf(expect) != -1) {\n                        isError = false;\n                        break;\n                    }\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.length() == 0 || proc.exitValue() == 0)\n                out = output.getOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamGobbler(error);\n            addStreamGobbler(output);\n\n            error = null;\n            output = null;\n\n            return new CommandResult(out, isError);\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            isError = true;\n            return new CommandResult(\"\", true);\n        }\n    }\n\n    public CommandResult executeCommand(String command, Pattern expect) {\n        return executeCommand(command, expect, 60 * 1000);\n    }\n\n    public CommandResult executeCommand(String command, Pattern expect, long timeout) {\n\n        StreamGobbler output = null;\n        StreamGobbler error = null;\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1 || osName.indexOf(\"Mac\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                isError = true;\n                return null;\n            }\n\n            error = getStreamGobbler();\n            output = getStreamGobbler();\n\n            // any error message?\n            error.setInputStream(proc.getErrorStream());\n\n            // any output?\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            // any error???\n            long startTime = System.currentTimeMillis();\n            while (true) {\n                try {\n                    out = error.getOutput();\n                    if (out != null && out.length() != 0 && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.getOutput();\n                    if (out != null && out.length() != 0) {\n                        if (expect.matcher(out).matches()) {\n                            isError = false;\n                            break;\n                        }\n                    }\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.length() == 0 || proc.exitValue() == 0)\n                out = output.getOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamGobbler(error);\n            addStreamGobbler(output);\n\n            error = null;\n            output = null;\n\n            return new CommandResult(out, isError);\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            return new CommandResult(\"\", true);\n        }\n    }\n\n    public CommandResult executeCommand(String command, String expect, int howManyTimes) {\n        return executeCommand(command, expect, howManyTimes, 60 * 1000);\n    }\n\n    public CommandResult executeCommand(String command, String expect, int howManyTimes, long timeout) {\n\n        StreamGobbler output = null;\n        StreamGobbler error = null;\n        int nr = 0; // how many times the expect string occured\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1 || osName.indexOf(\"Mac\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                return NullCommandResult;\n            }\n\n            error = getStreamGobbler();\n            output = getStreamGobbler();\n\n            error.setInputStream(proc.getErrorStream());\n\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            long startTime = System.currentTimeMillis();\n            while (true) {\n                try {\n                    out = error.getOutput();\n                    if (out != null && out.length() != 0 && proc.exitValue() != 0) {\n                        isError = true;\n                        break;\n                    }\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.getOutput();\n                    if (out != null && out.length() != 0 && out.indexOf(expect) != -1) {\n                        nr = getStringOccurences(out, expect);\n                        if (nr >= howManyTimes) {\n                            isError = false;\n                            break;\n                        }\n                    }\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            proc.destroy();\n            proc.waitFor();\n\n            if (out.length() == 0 || proc.exitValue() == 0)\n                out = output.getOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamGobbler(error);\n            addStreamGobbler(output);\n\n            error = null;\n            output = null;\n\n            return new CommandResult(out, isError);\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            return NullCommandResult;\n        }\n    }\n\n    protected int getStringOccurences(String text, String token) {\n\n        if (text.indexOf(token) < 0) return 0;\n        int nr = 0;\n        String str = text;\n        while (str.indexOf(token) >= 0) {\n            str = str.substring(str.indexOf(token) + token.length());\n            nr++;\n        }\n        return nr;\n    }\n\n    public CommandResult executeCommandReality(String command, String expect, String path) {\n        return executeCommandReality(command, expect, 60 * 1000, path);\n    }\n\n    public CommandResult executeCommandReality(String command, String expect, long timeout, String path) {\n\n        StreamRealGobbler error = null;\n        StreamRealGobbler output = null;\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                if (path != null && path.length() != 0)\n                    proc = Runtime.getRuntime().exec(cmd, new String[]{\"PATH=\" + path});\n                else\n                    proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                return NullCommandResult;\n            }\n\n            error = getStreamRealGobbler(timeout);\n            output = getStreamRealGobbler(timeout);\n\n            // any error message?\n            error.setInputStream(proc.getErrorStream());\n\n            // any output?\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            // any error???\n            long startTime = System.currentTimeMillis();\n            boolean timeoutOccured = false;\n            while (true) {\n                try {\n                    out = error.forceAllOutput();\n                    if (proc.exitValue() != 0) {\n                        isError = true;\n                    }\n                    break; // also if exitValue did not throw exception than we're done running\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.forceAllOutput();\n                    if (out != null && out.length() != 0 && out.indexOf(expect) != -1) {\n                        isError = false;\n                        proc.destroy();\n                        break;\n                    }\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    timeoutOccured = true;\n                    proc.destroy();\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            if (!timeoutOccured) {\n                proc.waitFor();\n            } else {\n                try {\n                    Thread.sleep(2000);\n                    proc.getOutputStream().close();\n                    proc.getInputStream().close();\n                    proc.getErrorStream().close();\n                } catch (Exception ex) {\n                }\n            }\n\n            if (out != null && out.length() == 0 || proc.exitValue() == 0) {\n                out = output.forceAllOutput();\n            }\n\n            if (timeoutOccured)\n                out += \"...Timeout\";\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamRealGobbler(error);\n            addStreamRealGobbler(output);\n\n            error = null;\n            output = null;\n\n            return new CommandResult(out, isError);\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamRealGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamRealGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            return NullCommandResult;\n        }\n    }\n\n    public void executeCommandRealityForFinish(String command, String path) {\n        executeCommandRealityForFinish(command, false, path);\n    }\n\n    public void executeCommandRealityForFinish(String command, final boolean showOutput, String path) {\n        executeCommandRealityForFinish(command, showOutput, 60 * 60 * 1000, path);\n    }\n\n    public boolean executeCommandRealityForFinish(String command, final boolean showOutput, long timeout, String path) {\n\n        StreamRealGobbler error = null;\n        StreamRealGobbler output = null;\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                if (path != null && path.length() != 0)\n                    proc = Runtime.getRuntime().exec(cmd, new String[]{\"PATH=\" + path});\n                else\n                    proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                return true;\n            }\n\n            if (showOutput) {\n                error = getStreamRealGobbler(timeout);\n                output = getStreamRealGobbler(timeout);\n                error.setProgress(true);\n                output.setProgress(true);\n                // any error message?\n                error.setInputStream(proc.getErrorStream());\n                // any output?\n                output.setInputStream(proc.getInputStream());\n                error.setProgress(false);\n                output.setProgress(false);\n            }\n\n            long startTime = System.currentTimeMillis();\n            boolean timeoutOccured = false;\n            while (true) {\n                try {\n                    if (proc.exitValue() != 0) {\n                        isError = true;\n                    }\n                    break; // also if exitValue did not throw exception than we're done running\n                } catch (IllegalThreadStateException ex) {\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    timeoutOccured = true;\n                    proc.destroy();\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            if (!timeoutOccured) {\n                proc.waitFor();\n            } else {\n                try {\n                    Thread.sleep(2000);\n                    proc.getOutputStream().close();\n                    proc.getInputStream().close();\n                    proc.getErrorStream().close();\n                } catch (Exception ex) {\n                }\n            }\n\n            if (showOutput) {\n                error.setProgress(false);\n                output.setProgress(false);\n                error.stopIt();\n                output.stopIt();\n                addStreamRealGobbler(error);\n                addStreamRealGobbler(output);\n                error = null;\n                output = null;\n            }\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            isError = true;\n            if (error != null) {\n                addStreamRealGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamRealGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n\n        }\n        return isError;\n    }\n\n    public CommandResult executeCommandReality(String command, String expect, int howManyTimes, String path) {\n        return executeCommandReality(command, expect, howManyTimes, 60 * 1000, path);\n    }\n\n    public CommandResult executeCommandReality(String command, String expect, int howManyTimes, long timeout, String path) {\n\n        StreamRealGobbler error = null;\n        StreamRealGobbler output = null;\n        boolean isError = false;\n        try {\n            String osName = System.getProperty(\"os.name\");\n            Process proc = null;\n\n            if (osName.indexOf(\"Win\") != -1) {\n                proc = Runtime.getRuntime().exec(command);\n            } else if (osName.indexOf(\"Linux\") != -1) {\n                String[] cmd = new String[3];\n                cmd[0] = \"/bin/sh\";\n                cmd[1] = \"-c\";\n                cmd[2] = command;\n                if (path != null && path.length() != 0)\n                    proc = Runtime.getRuntime().exec(cmd, new String[]{\"PATH=\" + path});\n                else\n                    proc = Runtime.getRuntime().exec(cmd);\n            } else {\n                return NullCommandResult;\n            }\n\n            error = getStreamRealGobbler(timeout);\n            output = getStreamRealGobbler(timeout);\n\n            error.setInputStream(proc.getErrorStream());\n\n            output.setInputStream(proc.getInputStream());\n\n            String out = \"\";\n\n            long startTime = System.currentTimeMillis();\n            boolean timeoutOccured = false;\n            while (true) {\n                try {\n                    out = error.forceAllOutput();\n                    if (out != null && out.length() != 0 && proc.exitValue() != 0) {\n                        isError = true;\n                    }\n                    break;\n                } catch (IllegalThreadStateException ex) {\n                }\n                if (expect != null) {\n                    out = output.forceAllOutput();\n                    if (out != null && out.length() != 0 && out.indexOf(expect) != -1) {\n                        int nr = getStringOccurences(out, expect);\n                        if (nr >= howManyTimes) {\n                            isError = false;\n                            proc.destroy();\n                            break;\n                        }\n                    }\n                }\n                long endTime = System.currentTimeMillis();\n                if (endTime - startTime > timeout) {\n                    isError = true;\n                    timeoutOccured = true;\n                    proc.destroy();\n                    break;\n                }\n                Thread.sleep(100);\n            }\n\n            if (!timeoutOccured) {\n                proc.waitFor();\n            } else {\n                try {\n                    Thread.sleep(2000);\n                    proc.getOutputStream().close();\n                    proc.getInputStream().close();\n                    proc.getErrorStream().close();\n                } catch (Exception ex) {\n                }\n            }\n\n            if (out != null && out.length() == 0 || proc.exitValue() == 0)\n                out = output.forceAllOutput();\n\n            error.stopIt();\n            output.stopIt();\n\n            addStreamRealGobbler(error);\n            addStreamRealGobbler(output);\n\n            error = null;\n            output = null;\n            return new CommandResult(out, isError);\n\n        } catch (Exception e) {\n            e.printStackTrace();\n\n            if (error != null) {\n                addStreamRealGobbler(error);\n                error.stopIt();\n                error = null;\n            }\n\n            if (output != null) {\n                addStreamRealGobbler(output);\n                output.stopIt();\n                output = null;\n            }\n            return NullCommandResult;\n        }\n    }\n\n    public StreamGobbler getStreamGobbler() {\n\n        synchronized (streams) {\n            if (streams.size() == 0) {\n                StreamGobbler stream = new StreamGobbler(null);\n                stream.start();\n                return stream;\n            }\n            return (StreamGobbler) streams.removeFirst();\n        }\n    }\n\n    public void addStreamGobbler(StreamGobbler stream) {\n\n        synchronized (streams) {\n            if (!stopStreams)\n                streams.addLast(stream);\n            else\n                stream.stopItForever();\n        }\n    }\n\n    public StreamRealGobbler getStreamRealGobbler(long timeout) {\n\n        synchronized (streamsReal) {\n            if (streamsReal.size() == 0) {\n                StreamRealGobbler stream = new StreamRealGobbler(null, timeout);\n                stream.start();\n                return stream;\n            }\n            StreamRealGobbler st = (StreamRealGobbler) streamsReal.removeFirst();\n            st.setTimeout(timeout);\n            return st;\n        }\n    }\n\n    public void addStreamRealGobbler(StreamRealGobbler stream) {\n\n        synchronized (streamsReal) {\n            if (!stopStreamsReal)\n                streamsReal.addLast(stream);\n            else\n                stream.stopItForever();\n        }\n    }\n\n    public void stopIt() {\n        synchronized (streams) {\n            stopStreams = true;\n\n            while (streams.size() > 0) {\n                StreamGobbler sg = (StreamGobbler) (streams.removeFirst());\n                sg.stopItForever();\n            }\n        }\n        synchronized (streamsReal) {\n            stopStreamsReal = true;\n\n            while (streamsReal.size() > 0) {\n                StreamRealGobbler sg = (StreamRealGobbler) (streamsReal.removeFirst());\n                sg.stopItForever();\n            }\n        }\n    }\n\n    public static class CommandResult {\n        private final String output;\n        private final boolean failed;\n\n        public CommandResult(String output, boolean wasError) {\n            this.output = output;\n            this.failed = wasError;\n        }\n\n        /**\n         * @return Returns the output.\n         */\n        public String getOutput() {\n            return output == null ? \"\" : output;\n        }\n\n        /**\n         * @return Returns the failed.\n         */\n        public boolean failed() {\n            return failed;\n        }\n\n    }\n\n    class StreamGobbler extends Thread {\n\n        InputStream is;\n        StringBuilder output;\n        boolean stop = false;\n        boolean stopForever = false;\n        boolean doneReading = false;\n\n        public StreamGobbler(InputStream is) {\n\n            super(\"Stream Gobler\");\n            this.is = is;\n            this.output = new StringBuilder();\n            this.setDaemon(true);\n        }\n\n        public void setInputStream(InputStream is) {\n\n            this.is = is;\n            output = new StringBuilder();\n            stop = false;\n            synchronized (this) {\n                doneReading = false;\n                notify();\n            }\n        }\n\n        public String getOutput() {\n            return output == null ? null : output.toString();\n        }\n\n        public synchronized String forceAllOutput() {\n\n            if (!doneReading)\n                return null;\n            doneReading = false;\n            return output == null ? null : output.toString();\n        }\n\n        public void stopIt() {\n\n            stop = true;\n        }\n\n        public void stopItForever() {\n            synchronized (this) {\n                stopForever = true;\n                notify();\n            }\n        }\n\n        public void run() {\n\n            while (true) {\n\n                synchronized (this) {\n                    while (is == null && !stopForever) {\n                        try {\n                            wait();\n                        } catch (Exception e) {\n                        }\n                    }\n                }\n\n                if (stopForever) {\n                    break;\n                }\n\n                try {\n                    InputStreamReader isr = new InputStreamReader(is);\n                    BufferedReader br = new BufferedReader(isr);\n                    String line = null;\n                    while (!stop && (line = br.readLine()) != null) {\n                        output.append(line);\n                    }\n                    synchronized (this) {\n                        doneReading = true;\n                    }\n                    is.close();\n                } catch (Exception ioe) {\n                    output = new StringBuilder();\n                }\n                is = null;\n            }\n        }\n    }\n\n    class StreamRealGobbler extends Thread {\n\n        final char[] buf;\n        InputStream is;\n        InputStreamReader isr;\n        StringBuilder output = new StringBuilder();\n        boolean stop = false;\n        boolean doneReading = false;\n        boolean stopForever = false;\n\n        private Thread thread = null;\n        private boolean showProgress = false;\n\n        private long timeout;\n\n        public StreamRealGobbler(InputStream is, long timeout) {\n\n            super(\"Stream Real Gobler\");\n            this.timeout = timeout;\n            this.is = is;\n            this.setDaemon(true);\n            buf = new char[32];\n        }\n\n        public void setTimeout(long timeout) {\n            this.timeout = timeout;\n        }\n\n        public void setInputStream(InputStream is) {\n\n            this.is = is;\n            output = new StringBuilder();\n            stop = false;\n            synchronized (buf) {\n                doneReading = false;\n                buf.notifyAll();\n            }\n        }\n\n        public void setProgress(boolean showProgress) {\n            this.showProgress = showProgress;\n        }\n\n        public String getOutput() {\n\n            return output == null ? null : output.toString();\n        }\n\n        public String forceAllOutput() {\n\n            if (!doneReading) {\n                try {\n                    if (!isr.ready()) {\n                        return null;\n                    }\n                } catch (Exception ex) {\n                }\n\n                try {\n                    thread.interrupt(); // force the thread out of sleep\n                } catch (Exception ex) {\n                }\n                synchronized (buf) {\n                    buf.notifyAll();\n                }\n                // otherwise let's give the output a chance to complete\n                long start = System.currentTimeMillis();\n                while (!doneReading) {\n                    try {\n                        Thread.sleep(200);\n                    } catch (Exception ex) {\n                    }\n                    if (doneReading) {\n                        return output == null ? null : output.toString();\n                    }\n                    long now = System.currentTimeMillis();\n                    if ((now - start) >= timeout) {\n                        return null; // last chance\n                    }\n                }\n            }\n            return output == null ? null : output.toString();\n        }\n\n        public void stopIt() {\n            try {\n                is.close();\n            } catch (Exception ex) {\n            }\n            try {\n                isr.close();\n            } catch (Exception ex) {\n            }\n            stop = true;\n        }\n\n        public void stopItForever() {\n            synchronized (buf) {\n                stopIt();\n                stopForever = true;\n                buf.notifyAll();\n            }\n        }\n\n        public void run() {\n\n            thread = Thread.currentThread();\n\n            while (true) {\n\n                synchronized (buf) {\n                    while (is == null && !stopForever) {\n                        try {\n                            buf.wait();\n                        } catch (Exception e) {\n                        }\n                    }\n                }\n\n                if (stopForever) {\n                    synchronized (buf) {\n                        doneReading = true;\n                    }\n                    break;\n                }\n\n                try {\n                    isr = new InputStreamReader(is);\n                    while (!stop) {\n                        try {\n                            final int ret = isr.read(buf);\n                            if (ret > 0) {\n                                final String nstr = new String(buf, 0, ret);\n                                if (showProgress) {\n                                    logger.info(nstr);\n                                }\n                                output.append(nstr);\n                            } else {\n                                break; // and of stream\n                            }\n                        } catch (Exception ex) {\n                            break;\n                        }\n                    }\n\n                    synchronized (buf) {\n                        doneReading = true;\n                    }\n                } catch (Exception ioe) {\n                    output = new StringBuilder();\n                }\n                try {\n                    is.close();\n                } catch (Exception ex) {\n                }\n                is = null;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/PatternUtil.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net;\n\nimport java.util.HashMap;\nimport java.util.regex.Pattern;\n\n/**\n * This module relies heavily on Pattern matching (it's safer that way), but also Pattern is a memory\n * consumer, so please use this class in order to retrieve a given Pattern. The main purpose of this\n * is to instantiate a pattern once in memory.\n *\n * @author Ciprian Dobre\n */\npublic class PatternUtil {\n\n    /**\n     * We only want to instantiante this class once, if necessary\n     */\n    protected static PatternUtil _p;\n    /**\n     * The mapping keys vs Patterns\n     */\n    protected final HashMap<String, Pattern> patterns = new HashMap<String, Pattern>();\n\n    /**\n     * Call this method in order to retrieve the Pattern associated with a given key.\n     *\n     * @param key     The key to identify the Pattern\n     * @param pattern The pattern to use if instantiation required\n     * @return The pattern\n     */\n    public static synchronized Pattern getPattern(final String key, final String pattern) {\n        return getPattern(key, pattern, false);\n    }\n\n    /**\n     * Call this method in order to retrieve the Pattern associated with a given key.\n     *\n     * @param key     The key to identify the Pattern\n     * @param pattern The pattern to use if instantiation required\n     * @param takeEOL Should EndOfLine character be taken into consideration ?\n     * @return The pattern\n     */\n    public static synchronized Pattern getPattern(final String key, final String pattern, final boolean takeEOL) {\n\n        if (key == null) return null; // for null key return a null pattern\n        if (_p == null) {\n            _p = new PatternUtil();\n            _p.patterns.put(\"Unknown command\", _p.getNoSuchCommand());\n        }\n        if (!_p.patterns.containsKey(key)) {\n            final Pattern p = takeEOL ? Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL) : Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);\n            _p.patterns.put(key, p);\n            return p;\n        }\n        return _p.patterns.get(key);\n    }\n\n    /**\n     * A high used pattern is the one used for recognizing of no such file pattern\n     */\n    protected Pattern getNoSuchCommand() {\n        return Pattern.compile(\"([No such file or directory|Operation not permitted|bad command line argument])+\", Pattern.CASE_INSENSITIVE);\n    }\n\n} // end of class PatternUtil\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/Statistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net;\n\nimport java.io.Serializable;\n\n/**\n * Super class of all networking statistics objects\n *\n * @author Ciprian Dobre\n */\npublic class Statistics implements Serializable {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n\n    /**\n     * The time the statistics were generated\n     */\n    protected long time;\n\n    public Statistics() {\n        time = System.currentTimeMillis();\n    }\n\n    public void updateTime() {\n        time = System.currentTimeMillis();\n    }\n\n    public final long getTime() {\n        return time;\n    }\n\n} // end of class Statistics\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/dev/InterfaceHandler.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.dev;\n\nimport lia.util.net.copy.monitoring.lisa.cmdExec;\nimport lia.util.net.copy.monitoring.lisa.cmdExec.CommandResult;\nimport lia.util.net.copy.monitoring.lisa.net.PatternUtil;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.PrintStream;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.text.NumberFormat;\nimport java.util.*;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * This class constructs a list containing all the network interfaces available, together with their properties\n *\n * @author Ciprian Dobre\n */\npublic class InterfaceHandler {\n\n    /**\n     * Different patterns used for output parsing\n     **/\n\n    protected static final String ifNamePattern = \"^(\\\\S+)\\\\s+\";\n    protected static final String hwAddrPattern = \"HWaddr\\\\s+(\\\\S+)\";\n    protected static final String ipv4Pattern = \"inet addr:(\\\\S+)\";\n    protected static final String mask4Pattern = \"Mask:(\\\\S+)\";\n    protected static final String bcast4Pattern = \"Bcast:(\\\\S+)\";\n    protected static final String mtuPattern = \"MTU:(\\\\S+)\";\n    protected static final String rxPackets = \"RX[\\\\s\\\\S]+packets:(\\\\S+)\";\n    protected static final String rxErrors = \"RX[\\\\s\\\\S]+errors:(\\\\S+)\";\n    protected static final String rxDropped = \"RX[\\\\s\\\\S]+dropped:(\\\\S+)\";\n    protected static final String rxOverruns = \"RX[\\\\s\\\\S]+overruns:(\\\\S+)\";\n    protected static final String rxFrame = \"RX[\\\\s\\\\S]+frame:(\\\\S+)\";\n    protected static final String rxBytes = \"RX\\\\s+bytes:(\\\\S+)\";\n    protected static final String txPackets = \"TX[\\\\s\\\\S]+packets:(\\\\S+)\";\n    protected static final String txErrors = \"TX[\\\\s\\\\S]+errors:(\\\\S+)\";\n    protected static final String txDropped = \"TX[\\\\s\\\\S]+dropped:(\\\\S+)\";\n    protected static final String txOverruns = \"TX[\\\\s\\\\S]+overruns:(\\\\S+)\";\n    protected static final String txCarrier = \"TX[\\\\s\\\\S]+carrier:(\\\\S+)\";\n    protected static final String txBytes = \"TX\\\\s+bytes:(\\\\S+)\";\n    protected static final String collisions = \"\\\\s+collisions:(\\\\S+)\";\n    protected static final String compressed = \"\\\\s+compressed:(\\\\S+)\";\n    protected static final String txqueuelen = \"\\\\s+txqueuelen:(\\\\S+)\";\n    protected static final String netDevPattern = \"(\\\\S+):\\\\s*(\\\\d+)\\\\s+(\\\\d+)\\\\s+(\\\\d+)\\\\s+(\\\\d+)\\\\s+(\\\\d+)\\\\s+\";\n    protected static final String supportedPortsPattern = \"Supported ports:\\\\s*\\\\[(.*)\\\\]\";\n    protected static final String supportedLinkModes = \"Supported link modes:\\\\s*(.*?)Supports\";\n    protected static final String supportsAutoNegotiation = \"Supports auto-negotiation:\\\\s*(\\\\S+)\";\n    protected static final String speed = \"Speed:\\\\s*(.*)\";\n    protected static final String duplex = \"Duplex:\\\\s*(.*)\";\n    protected static final String port = \"Port:\\\\s*(.*)\";\n    final static NumberFormat nf = NumberFormat.getInstance();\n\n    static {\n        nf.setMaximumFractionDigits(4);\n        nf.setMinimumFractionDigits(4);\n    }\n\n    /**\n     * Utility object used for running different commands\n     */\n    protected final cmdExec exec;\n    /**\n     * The stream to write output to\n     */\n    protected final PrintStream out;\n    protected final Hashtable<String, String> lastRXPackets = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastRXErrors = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastRXDropped = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastRXOverruns = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastRXFrame = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastRXBytes = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXPackets = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXErrors = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXDropped = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXOverruns = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXCarrier = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastTXBytes = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastCollisions = new Hashtable<String, String>();\n    protected final Hashtable<String, String> lastCompressed = new Hashtable<String, String>();\n    /**\n     * The interfaces of the system toghether with the monitored properties\n     */\n    protected final HashMap<String, InterfaceStatistics> ifs = new HashMap<String, InterfaceStatistics>();\n    protected final HashMap<String, InterfaceStatisticsStatic> lastGoodStatic = new HashMap<String, InterfaceStatisticsStatic>();\n    protected final HashMap<String, InterfaceStatisticsStatic> staticifs = new HashMap<String, InterfaceStatisticsStatic>();\n    protected final Logger logger;\n    /**\n     * some temporary variables ... we only want them to be instantiated once because of the latency involved\n     */\n    final List<String> ifArray = new ArrayList<String>();\n    final List<String> toRemove = new ArrayList<String>();\n    protected long lastCall = 0;\n    /**\n     * is this a 64 bits arch ?\n     */\n    private boolean is64BitArch = false;\n\n    /**\n     * The constructor\n     *\n     * @param out        The stream to write output to\n     */\n    public InterfaceHandler(final PrintStream out, final Logger logger) {\n        this.logger = logger;\n        this.out = out;\n        exec = cmdExec.getInstance();\n    }\n\n    public static void main(String args[]) {\n\n        String line = \"Speed: Unknown (100000)\\nTest\\n\";\n        Pattern pattern = PatternUtil.getPattern(\"supportedLinkModes\", speed);\n        Matcher matcher = pattern.matcher(line);\n        if (matcher.find()) {\n            System.out.println(matcher.group(1));\n        } else\n            System.out.println(\"no match\");\n    }\n\n    /**\n     * Return the current declared path of the ifconfig utility (default to /sbin)\n     *\n     * @return The path to ifconfig utility.\n     */\n    private synchronized final String getIfconfigPath() {\n        String path = System.getProperty(\"net.ifconfig.path\", \"/bin,/sbin,/usr/bin,/usr/sbin\");\n        if (path == null || path.length() == 0) {\n            logger.warning(\"[Net - iconfig can not be found in \" + path + \"]\");\n            return null;\n        }\n        return path.replace(',', ':').trim();\n    }\n\n    /**\n     * A method that can be used to check for the encapsulation type of a link\n     *\n     * @param props    (Option) The properties to put the type into\n     * @param ifOutput The output of the ifconfig utility\n     * @return False if the encapsulation type is of no interest (for example loopback interface)\n     */\n    private final boolean checkLinkEncap(final InterfaceStatisticsStatic props, final String ifOutput) {\n\n        if (ifOutput == null || ifOutput.length() == 0) return false;\n        if (ifOutput.contains(\"Link encap:Ethernet\")) {\n            if (props != null) props.setEncap(InterfaceStatisticsStatic.TYPE_ETHERNET);\n            return true;\n        }\n        if (ifOutput.contains(\"Link encap:Fiber Distributed Data Interface\")) {\n            if (props != null) props.setEncap(InterfaceStatisticsStatic.TYPE_FIBER);\n            return true;\n        }\n        // TODO maybe we should consider:\n        // HIPPI: http://www.rfc-editor.org/rfc/rfc1374.txt\n        // AX.25, X.25, Token Ring, Frame Relay, ISDN, HDLC, PPP, Econet\n        return false;\n    }\n\n    /**\n     * The part used for ifconfig\n     */\n    private final void checkIfConfig() {\n        final String ifc = getIfconfigPath();\n        final String command = \"ifconfig\";\n        CommandResult cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        final String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n            return;\n        }\n\n        double diff = 0D;\n        long now = System.currentTimeMillis();\n        if (lastCall != 0) {\n            diff = (now - lastCall) / 1000D;\n        }\n        lastCall = now;\n\n        // otherwise we have ifconfig and can also be used\n        final String interfaces[] = ret.split(\"\\n\\n\");\n        ifArray.clear();\n        for (int i = 0; i < interfaces.length; i++) {\n            Pattern pattern = PatternUtil.getPattern(\"ifname\", ifNamePattern);\n            Matcher matcher = pattern.matcher(interfaces[i]);\n            InterfaceStatistics ifProp = null;\n            InterfaceStatisticsStatic ifPropStatic = null;\n            String name = null;\n            if (matcher.find()) {\n                name = matcher.group(1);\n                ifArray.add(name);\n                if (!ifs.containsKey(name)) {\n                    ifProp = new InterfaceStatistics(name);\n                    ifs.put(name, ifProp);\n                } else {\n                    ifProp = ifs.get(name);\n                    ifProp.updateTime();\n                }\n                if (!staticifs.containsKey(name)) {\n                    ifPropStatic = new InterfaceStatisticsStatic(name);\n                    staticifs.put(name, ifPropStatic);\n                } else {\n                    ifPropStatic = staticifs.get(name);\n                    ifPropStatic.updateTime();\n                }\n                if (!checkLinkEncap(ifPropStatic, interfaces[i])) { // if not an interface to be interested in...\n                    ifArray.remove(name); // to be removed\n                    continue; // continue with the next interface\n                }\n            } else {\n                continue; // continue with the next interface\n            }\n            pattern = PatternUtil.getPattern(\"hwaddr\", hwAddrPattern);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                ifPropStatic.setHwAddr(matcher.group(1));\n            } else\n                ifPropStatic.setHwAddr(\"unknown\");\n            pattern = PatternUtil.getPattern(\"ipv4\", ipv4Pattern);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                ifProp.setIPv4(matcher.group(1));\n            } else\n                ifProp.setIPv4(\"unknown\");\n            pattern = PatternUtil.getPattern(\"mask4\", mask4Pattern);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                ifProp.setMaskv4(matcher.group(1));\n            } else\n                ifProp.setMaskv4(\"unknown\");\n            pattern = PatternUtil.getPattern(\"bcast4\", bcast4Pattern);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                ifProp.setBcastv4(matcher.group(1));\n            } else\n                ifProp.setBcastv4(\"unknown\");\n            // TODO also add information regarding ipv6\n            pattern = PatternUtil.getPattern(\"mtu\", mtuPattern);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                try {\n                    ifProp.setMTU(Integer.parseInt(matcher.group(1)));\n                } catch (Exception ex) {\n                    ifProp.setMTU(-1);\n                }\n            } else\n                ifProp.setMTU(-1);\n            pattern = PatternUtil.getPattern(\"rxpackets\", rxPackets);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXPackets.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRXPackets((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRXPackets(-1D);\n                    }\n                }\n                lastRXPackets.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"rxerrors\", rxErrors);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXErrors.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRXErrors((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRXErrors(-1D);\n                    }\n                }\n                lastRXErrors.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"rxdropped\", rxDropped);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXDropped.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRXDropped((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRXDropped(-1D);\n                    }\n                }\n                lastRXDropped.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"rxoverruns\", rxOverruns);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXOverruns.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRXOverruns((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRXOverruns(-1D);\n                    }\n                }\n                lastRXOverruns.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"rxframe\", rxFrame);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXFrame.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRXFrame((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRXFrame(-1D);\n                    }\n                }\n                lastRXFrame.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"rxBytes\", rxBytes);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastRXBytes.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setRX((double) difRes * 8D / diff);\n                    } catch (Throwable t) {\n                        ifProp.setRX(-1D);\n                    }\n                }\n                lastRXBytes.put(name, newVal);\n            }\n\n            pattern = PatternUtil.getPattern(\"txpackets\", txPackets);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXPackets.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTXPackets((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTXPackets(-1D);\n                    }\n                }\n                lastTXPackets.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"txerrors\", txErrors);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXErrors.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTXErrors((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTXErrors(-1D);\n                    }\n                }\n                lastTXErrors.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"txdropped\", txDropped);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXDropped.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTXDropped((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTXDropped(-1D);\n                    }\n                }\n                lastTXDropped.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"txoverruns\", txOverruns);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXOverruns.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTXOverruns((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTXOverruns(-1D);\n                    }\n                }\n                lastTXOverruns.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"txcarrier\", txCarrier);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXCarrier.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTXCarrier((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTXCarrier(-1D);\n                    }\n                }\n                lastTXCarrier.put(name, newVal);\n            }\n            pattern = PatternUtil.getPattern(\"txBytes\", txBytes);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastTXBytes.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setTX((double) difRes * 8D / diff);\n                    } catch (Throwable t) {\n                        ifProp.setTX(-1D);\n                    }\n                }\n                lastTXBytes.put(name, newVal);\n            }\n\n            pattern = PatternUtil.getPattern(\"collisions\", collisions);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastCollisions.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setCollisions((double) difRes / diff);\n                    } catch (Throwable t) {\n                        ifProp.setCollisions(-1D);\n                    }\n                }\n                lastCollisions.put(name, newVal);\n            }\n\n            pattern = PatternUtil.getPattern(\"compressed\", compressed);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                if (diff > 0) {\n                    String res = diffWithOverflowCheck(newVal, lastCompressed.get(name));\n                    try {\n                        double difRes = Double.parseDouble(res);\n                        ifProp.setCompressed((double) difRes / diff);\n                        ifProp.setCanCompress(true);\n                    } catch (Throwable t) {\n                        ifProp.setCompressed(-1D);\n                    }\n                }\n                lastCompressed.put(name, newVal);\n            } else\n                ifProp.setCanCompress(false);\n\n            pattern = PatternUtil.getPattern(\"txqueuelen\", txqueuelen);\n            matcher = pattern.matcher(interfaces[i]);\n            if (matcher.find()) {\n                String newVal = matcher.group(1);\n                try {\n                    ifProp.setTXQueueLen(Integer.parseInt(newVal));\n                } catch (Exception e) {\n                    ifProp.setTXQueueLen(-1);\n                }\n            }\n\n        }\n        // finnaly if some interfaces were removed, than better remove their properties also\n        toRemove.clear();\n        for (Iterator it = ifs.keySet().iterator(); it.hasNext(); ) {\n            String ifn = (String) it.next();\n            if (!ifArray.contains(ifn)) toRemove.add(ifn);\n        }\n        for (String ifn : toRemove) {\n            ifs.remove(ifn);\n            staticifs.remove(ifn);\n        }\n\n//\t\tfor (Map.Entry<String, InterfaceStatistics> entry : ifs.entrySet()) {\n//\t\t\tlogger.info(entry.getValue().toString());\n//\t\t}\n    }\n\n    public void modify(TXQueueLenSet set) {\n\n        String ifc = getIfconfigPath();\n\n        // get the previous value first\n        String previoustx = null;\n        String command = \"ifconfig \" + set.ifName;\n        CommandResult cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n        } else {\n            final Pattern pattern = PatternUtil.getPattern(\"txqueuelen\", txqueuelen);\n            final Matcher matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                previoustx = matcher.group(1);\n            }\n        }\n\n        // try to change it while running first....\n        command = \"ifconfig \" + set.ifName + \" txqueuelen \" + set.txqueuelen;\n        cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        ret = cmdRes.getOutput();\n        boolean done = true;\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n            done = false;\n        }\n        if (done) {\n            // check the result...\n            command = \"ifconfig \" + set.ifName;\n            cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n            ret = cmdRes.getOutput();\n            if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n                if (out != null)\n                    out.println(ret);\n                else\n                    logger.info(ret);\n                done = false;\n            }\n            if (done) {\n                final Pattern pattern = PatternUtil.getPattern(\"txqueuelen\", txqueuelen);\n                final Matcher matcher = pattern.matcher(ret);\n                if (matcher.find()) {\n                    String newVal = matcher.group(1);\n                    if (previoustx == null) return; // everything is set\n                    done = !previoustx.equals(newVal);\n                }\n            }\n        }\n        if (done)\n            return;\n\n        // now change it by doing ifdown, ifup\n        doIfDown(set.ifName);\n        command = \"ifconfig \" + set.ifName + \" txqueuelen \" + set.txqueuelen;\n        cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n        }\n        doIfUp(set.ifName);\n    }\n\n    public void modify(MTUSet set) {\n\n        String ifc = getIfconfigPath();\n\n        // get the previous value first\n        String previousmtu = null;\n        String command = \"ifconfig \" + set.ifName;\n        CommandResult cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n        } else {\n            final Pattern pattern = PatternUtil.getPattern(\"mtu\", mtuPattern);\n            final Matcher matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                previousmtu = matcher.group(1);\n            }\n        }\n\n        // try to change it while running first....\n        command = \"ifconfig \" + set.ifName + \" mtu \" + set.mtu;\n        cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        ret = cmdRes.getOutput();\n        boolean done = true;\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n            done = false;\n        }\n        if (done) {\n            // check the result...\n            command = \"ifconfig \" + set.ifName;\n            cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n            ret = cmdRes.getOutput();\n            if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n                if (out != null)\n                    out.println(ret);\n                else\n                    logger.info(ret);\n                done = false;\n            }\n            if (done) {\n                final Pattern pattern = PatternUtil.getPattern(\"mtu\", mtuPattern);\n                final Matcher matcher = pattern.matcher(ret);\n                if (matcher.find()) {\n                    String newVal = matcher.group(1);\n                    if (previousmtu == null) return; // everything is set\n                    done = !previousmtu.equals(newVal);\n                }\n            }\n        }\n        if (done)\n            return;\n\n        // now change it by doing ifdown, ifup\n        doIfDown(set.ifName);\n        command = \"ifconfig \" + set.ifName + \" mtu \" + set.mtu;\n        cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n        }\n        doIfUp(set.ifName);\n    }\n\n    private void doIfDown(String ifName) {\n\n        final String ifc = getIfconfigPath();\n        final String command = \"ifconfig down\";\n        final CommandResult cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        final String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n\n            return;\n        }\n    }\n\n    private void doIfUp(String ifName) {\n\n        final String ifc = getIfconfigPath();\n        final String command = \"ifconfig up\";\n        final CommandResult cmdRes = exec.executeCommandReality(command, (String) null, ifc);\n        final String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null)\n                out.println(ret);\n            else\n                logger.info(ret);\n\n            return;\n        }\n    }\n\n    /**\n     * Called in order to check if we should use ethtool utility\n     *\n     * @return False if net.ethtool.use is set to false\n     */\n    private final boolean shouldRunEthTool() {\n        String prop = System.getProperty(\"net.ethtool.use\", null);\n        if (prop == null)\n            return true;\n        try {\n            return Boolean.getBoolean(prop);\n        } catch (Throwable t) {\n        }\n        return true;\n    }\n\n    private synchronized final String getEthtoolPath() {\n        String path = System.getProperty(\"net.ethtool.path\", \"/bin,/sbin,/usr/bin,/usr/sbin\");\n        if (path == null || path.length() == 0) {\n            logger\n                    .warning(\"[Net - ethtool can not be found in \" + path\n                            + \"]\");\n            return null;\n        }\n        return path.replace(',', ':').trim();\n    }\n\n    /**\n     * The part used for mii-tool\n     */\n    private final void checkEthtool() {\n\n        final String eth = getEthtoolPath();\n        final String command = \"ethtool \";\n        for (Map.Entry<String, InterfaceStatisticsStatic> entry : staticifs.entrySet()) {\n            final String ifName = entry.getKey();\n            final InterfaceStatisticsStatic stat = entry.getValue();\n            if (ifName == null || ifName.length() == 0 || stat == null) continue;\n            final CommandResult cmdRes = exec.executeCommandReality(command + ifName, null, eth);\n            final String ret = cmdRes.getOutput();\n            if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n                if (out != null) {\n                    out.println(ret);\n                } else {\n                    if (logger.isLoggable(Level.FINER))\n                        logger.log(Level.FINE, ret);\n                }\n                continue;\n            }\n            stat.setSupportedPorts((byte) 0);\n\n            Pattern pattern = PatternUtil.getPattern(\"supportedPorts\", supportedPortsPattern);\n            Matcher matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm.trim().length() != 0) {\n                    final String sp[] = mm.trim().split(\" \");\n                    for (int k = 0; k < sp.length; k++) {\n                        if (sp[k].equals(\"TP\"))\n                            stat.setSupportedPorts(InterfaceStatisticsStatic.PORT_TP);\n                        if (sp[k].equals(\"AUI\"))\n                            stat.setSupportedPorts(InterfaceStatisticsStatic.PORT_AUI);\n                        if (sp[k].equals(\"BNC\"))\n                            stat.setSupportedPorts(InterfaceStatisticsStatic.PORT_BNC);\n                        if (sp[k].equals(\"MII\"))\n                            stat.setSupportedPorts(InterfaceStatisticsStatic.PORT_MII);\n                        if (sp[k].equals(\"FIBRE\"))\n                            stat.setSupportedPorts(InterfaceStatisticsStatic.PORT_FIBRE);\n                    }\n                }\n            }\n            pattern = PatternUtil.getPattern(\"supportedLinkModes\", supportedLinkModes, true);\n            matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm.trim().length() != 0) {\n                    final String sp[] = mm.trim().split(\"[ \\n]+\");\n                    for (int k = 0; k < sp.length; k++) {\n                        if (sp[k].trim().length() == 0) continue;\n                        final String ss = sp[k].trim();\n                        if (ss.equals(\"10baseT/Half\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_10BaseT_Half);\n                        if (ss.equals(\"10baseT/Full\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_10BaseT_Full);\n                        if (ss.equals(\"100baseT/Half\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_100BaseT_Half);\n                        if (ss.equals(\"100baseT/Full\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_100BaseT_Full);\n                        if (ss.equals(\"1000baseT/Half\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_1000BaseT_Half);\n                        if (ss.equals(\"1000baseT/Full\"))\n                            stat.setSupportedLinkModes(InterfaceStatisticsStatic.SUPPORTED_1000BaseT_Full);\n                    }\n                }\n            }\n            pattern = PatternUtil.getPattern(\"supportsAutoNegotiation\", supportsAutoNegotiation);\n            matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm.trim().length() != 0) {\n                    if (mm.trim().equals(\"Yes\"))\n                        stat.setSupportsAutoNegotiation(true);\n                }\n            }\n            pattern = PatternUtil.getPattern(\"linkSpeed\", speed);\n            matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm != null && mm.trim().length() != 0) {\n                    final String ss = mm.trim();\n                    if (ss.equals(\"10Mb/s\"))\n                        stat.setMaxSpeed(10);\n                    else if (ss.equals(\"100Mb/s\"))\n                        stat.setMaxSpeed(100);\n                    else if (ss.equals(\"1000Mb/s\"))\n                        stat.setMaxSpeed(1000);\n                    else if (ss.equals(\"10000Mb/s\"))\n                        stat.setMaxSpeed(10000);\n                    else if (ss.startsWith(\"Unknown\")) {\n                        final String sp = ss.substring(ss.indexOf('(') + 1, ss.lastIndexOf(')'));\n                        try {\n                            stat.setMaxSpeed(Integer.parseInt(sp));\n                        } catch (Exception ex) {\n                            logger.warning(\"Can not determine speed \" + ss + \" for \" + ifName);\n                        }\n                    }\n                }\n            }\n            pattern = PatternUtil.getPattern(\"linkDuplex\", duplex);\n            matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm != null && mm.trim().length() != 0) {\n                    final String ss = mm.trim();\n                    if (ss.compareToIgnoreCase(\"Half\") == 0) {\n                        stat.setDuplex(InterfaceStatisticsStatic.LINK_HALF);\n                    } else if (ss.compareToIgnoreCase(\"Full\") == 0) {\n                        stat.setDuplex(InterfaceStatisticsStatic.LINK_DUPLEX);\n                    }\n                }\n            }\n            pattern = PatternUtil.getPattern(\"linkPort\", port);\n            matcher = pattern.matcher(ret);\n            if (matcher.find()) {\n                final String mm = matcher.group(1);\n                if (mm != null && mm.trim().length() != 0) {\n                    final String ss = mm.trim();\n                    if (ss.compareTo(\"Twisted Pair\") == 0) {\n                        stat.setPort(InterfaceStatisticsStatic.PORT_TP);\n                    } else if (ss.compareToIgnoreCase(\"FIBRE\") == 0) {\n                        stat.setPort(InterfaceStatisticsStatic.PORT_FIBRE);\n                    } else if (ss.compareToIgnoreCase(\"AUI\") == 0) {\n                        stat.setPort(InterfaceStatisticsStatic.PORT_AUI);\n                    } else if (ss.compareToIgnoreCase(\"BNC\") == 0) {\n                        stat.setPort(InterfaceStatisticsStatic.PORT_BNC);\n                    } else if (ss.compareToIgnoreCase(\"MII\") == 0) {\n                        stat.setPort(InterfaceStatisticsStatic.PORT_MII);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * This is used to check for network interface devices locally by looking into\n     * /proc/net/dev - is used only if ifconfig fails to speed up things\n     */\n    private final void getFromProcDev() {\n        ifArray.clear();\n        final Pattern pattern = PatternUtil.getPattern(\"/proc/net/dev\", netDevPattern);\n        try {\n            BufferedReader reader = new BufferedReader(new FileReader(\"/proc/net/dev\"));\n            String line;\n            while ((line = reader.readLine()) != null) {\n                final Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    final String ifName = matcher.group(1);\n                    ifArray.add(ifName);\n                    if (!ifs.containsKey(ifName)) {\n                        ifs.put(ifName, new InterfaceStatistics(ifName));\n                    } else\n                        ifs.get(ifName).updateTime();\n                }\n            }\n            reader.close();\n        } catch (Exception e) {\n        }\n\n        // finnaly if some interfaces were removed, than better remove their properties also\n        toRemove.clear();\n        for (Iterator it = ifs.keySet().iterator(); it.hasNext(); ) {\n            String ifn = (String) it.next();\n            if (!ifArray.contains(ifn)) toRemove.add(ifn);\n        }\n        for (String ifn : toRemove) {\n            ifs.remove(ifn);\n        }\n    }\n\n    private final boolean compare(InterfaceStatisticsStatic olds, InterfaceStatisticsStatic news) {\n        if (olds.getEncap() != news.getEncap()) return false;\n        if (olds.getHwAddr() == null && news.getHwAddr() != null) return false;\n        if (olds.getHwAddr() != null && news.getHwAddr() == null) return false;\n        if (olds.getHwAddr() != null && news.getHwAddr() != null)\n            if (!olds.getHwAddr().equals(news.getHwAddr())) return false;\n        if (olds.getSupportedPorts() != news.getSupportedPorts()) return false;\n        if (olds.getSupportedLinkModes() != news.getSupportedLinkModes()) return false;\n        if (olds.supportsAutoNegotiation() != news.supportsAutoNegotiation()) return false;\n        if (olds.getMaxSpeed() != news.getMaxSpeed()) return false;\n        if (olds.getDuplex() != news.getDuplex()) return false;\n        if (olds.getPort() != news.getPort()) return false;\n        return true;\n    }\n\n    /**\n     * Action method for this task... retrieves the network interfaces together with their properties ...\n     */\n    public final void check() {\n        checkIfConfig();\n        if (ifs.size() == 0) { // no interface yet? let's read /proc/net/dev also\n            getFromProcDev();\n        }\n        if (ifs.size() == 0) return; // so there really is no net device installed into the system\n        if (shouldRunEthTool())\n            checkEthtool();\n\n        final LinkedList<String> names = new LinkedList<String>();\n        for (Map.Entry<String, InterfaceStatisticsStatic> entry : lastGoodStatic.entrySet()) {\n            names.addLast(entry.getKey());\n        }\n        for (String name : names) {\n            if (!staticifs.containsKey(name))\n                lastGoodStatic.remove(name);\n        }\n        names.clear();\n        for (Map.Entry<String, InterfaceStatisticsStatic> entry : staticifs.entrySet()) {\n            names.addLast(entry.getKey());\n        }\n        for (String name : names) {\n            if (!lastGoodStatic.containsKey(name)) {\n                lastGoodStatic.put(name, staticifs.get(name));\n                continue;\n            }\n            final InterfaceStatisticsStatic olds = lastGoodStatic.get(name);\n            final InterfaceStatisticsStatic news = staticifs.get(name);\n\n            if (!compare(olds, news)) {\n                lastGoodStatic.put(name, news);\n            } else {\n                staticifs.remove(name);\n            }\n        }\n    }\n\n    public final HashMap<String, InterfaceStatistics> getIfStatistics() {\n        return ifs;\n    }\n\n    public final HashMap<String, InterfaceStatisticsStatic> getOldIfStatisticsStatic() {\n        return lastGoodStatic;\n    }\n\n    public final HashMap<String, InterfaceStatisticsStatic> getIfStatisticsStatic() {\n        return staticifs;\n    }\n\n    public String diffWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            if (newv.compareTo(oldv) >= 0)\n                return newv.subtract(oldv).toString();\n            BigInteger overflow = new BigInteger(\"1\").shiftLeft(64);\n            BigDecimal d = new BigDecimal(overflow.toString());\n            return newv.add(d).subtract(oldv).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return diffWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        if (newv >= oldv) {\n            return \"\" + (newv - oldv);\n        }\n        long vmax = 1L << 32; // 32 bits\n        return \"\" + (newv - oldv + vmax);\n    }\n\n    public String divideWithOverflowCheck(String newVal, String oldVal) throws NumberFormatException {\n\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.divide(oldv, BigDecimal.ROUND_FLOOR).toString();\n        }\n        // otherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return divideWithOverflowCheck(newVal, oldVal);\n        }\n        // so it's still 32 bits arch\n        return \"\" + (newv / oldv);\n    }\n\n    private final String prepareString(String str) {\n\n        // first try to make it double\n        try {\n            double d = Double.parseDouble(str);\n            if (!Double.isInfinite(d) && !Double.isNaN(d)) {\n                String n = nf.format(d);\n                n = n.replaceAll(\",\", \"\");\n                return n;\n            }\n        } catch (Throwable t) {\n        }\n\n        if (!str.contains(\".\")) {\n            return str + \".0000\";\n        }\n        int nr = str.lastIndexOf('.') + 1;\n        nr = str.length() - nr;\n        for (int i = nr; i < 4; i++)\n            str += \"0\";\n        return str;\n    }\n\n    /**\n     * Called in order to clear some memory when needed\n     */\n    public void clear() {\n        ifs.clear();\n        staticifs.clear();\n    }\n\n} // end of class InterfaceHandler\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/dev/InterfaceStatistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.dev;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\n/**\n * Wrapper class that encapsulated the properties of a network interface..\n *\n * @author Ciprian Dobre\n */\npublic class InterfaceStatistics extends Statistics {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    /**\n     * The name of the interface\n     */\n    protected final String name;\n\n    /** For IPv4 */\n\n    /**\n     * The IPv4 network address in use\n     */\n    protected String ipv4;\n\n    /**\n     * The IPv4 broadcast domain\n     */\n    protected String bcastipv4;\n\n    /**\n     * The IPV4 mask\n     */\n    protected String maskipv4;\n\n    /**\n     * MTU\n     */\n    protected int mtu = 1500;\n\n    /**\n     * For RX\n     */\n\n    protected double rxPackets = 0D;\n    protected double rxErrors = 0D;\n    protected double rxDropped = 0D;\n    protected double rxOverruns = 0D;\n    protected double rxFrame = 0D;\n    protected double rx = 0D;\n\n    /**\n     * For TX\n     */\n\n    protected double txPackets = 0D;\n    protected double txErrors = 0D;\n    protected double txDropped = 0D;\n    protected double txOverruns = 0D;\n    protected double txCarrier = 0D;\n    protected double tx = 0D;\n\n    /**\n     * General statistics\n     */\n    protected double collisions = 0D;\n    protected boolean canCompress = false;\n    protected double compressed = 0D;\n    protected int txqueuelen = 0;\n\n    /**\n     * The constructor - only the name is final\n     */\n    public InterfaceStatistics(final String name) {\n        super();\n        this.name = name;\n    }\n\n    /**\n     * Method used to retrieve the name of the interface\n     */\n    public final String getName() {\n        return name;\n    }\n\n    /**\n     * Getter for the network address IPv4\n     */\n    public final String getIPv4() {\n        return ipv4;\n    }\n\n    /**\n     * Setter for the network address IPv4\n     */\n    public final void setIPv4(final String address) {\n        this.ipv4 = address;\n    }\n\n    /**\n     * Getter for the bcast address IPv4\n     */\n    public final String getBcastv4() {\n        return bcastipv4;\n    }\n\n    /**\n     * Setter for the bcast address IPv4\n     */\n    public final void setBcastv4(final String bcast) {\n        this.bcastipv4 = bcast;\n    }\n\n    /**\n     * Getter for the network mask IPv4\n     */\n    public final String getMaskv4() {\n        return maskipv4;\n    }\n\n    /**\n     * Setter for the network mask IPv4\n     */\n    public final void setMaskv4(final String mask) {\n        this.maskipv4 = mask;\n    }\n\n    /**\n     * Getter for mtu\n     */\n    public final int getMTU() {\n        return mtu;\n    }\n\n    /**\n     * Setter for mtu\n     */\n    public final void setMTU(final int mtu) {\n        this.mtu = mtu;\n    }\n\n    public final double getRX() {\n        return rx;\n    }\n\n    public final void setRX(final double rx) {\n        this.rx = rx;\n    }\n\n    public final double getRXPackets() {\n        return rxPackets;\n    }\n\n    public final void setRXPackets(final double packets) {\n        this.rxPackets = packets;\n    }\n\n    public final double getRXErrors() {\n        return rxErrors;\n    }\n\n    public final void setRXErrors(final double errors) {\n        this.rxErrors = errors;\n    }\n\n    public final double getRXDropped() {\n        return rxDropped;\n    }\n\n    public final void setRXDropped(final double dropped) {\n        this.rxDropped = dropped;\n    }\n\n    public final double getRXOverruns() {\n        return rxOverruns;\n    }\n\n    public final void setRXOverruns(final double overruns) {\n        this.rxOverruns = overruns;\n    }\n\n    public final double getRXFrame() {\n        return rxFrame;\n    }\n\n    public final void setRXFrame(final double frame) {\n        this.rxFrame = frame;\n    }\n\n    public final double getTX() {\n        return tx;\n    }\n\n    public final void setTX(final double tx) {\n        this.tx = tx;\n    }\n\n    public final double getTXPackets() {\n        return txPackets;\n    }\n\n    public final void setTXPackets(final double packets) {\n        this.txPackets = packets;\n    }\n\n    public final double getTXErrors() {\n        return txErrors;\n    }\n\n    public final void setTXErrors(final double errors) {\n        this.txErrors = errors;\n    }\n\n    public final double getTXDropped() {\n        return txDropped;\n    }\n\n    public final void setTXDropped(final double dropped) {\n        this.txDropped = dropped;\n    }\n\n    public final double getTXOverruns() {\n        return txOverruns;\n    }\n\n    public final void setTXOverruns(final double overruns) {\n        this.txOverruns = overruns;\n    }\n\n    public final double getTXCarrier() {\n        return txCarrier;\n    }\n\n    public final void setTXCarrier(final double carrier) {\n        this.txCarrier = carrier;\n    }\n\n    public final double getCompressed() {\n        return compressed;\n    }\n\n    public final void setCompressed(final double compressed) {\n        this.compressed = compressed;\n    }\n\n    public final boolean getCanCompress() {\n        return canCompress;\n    }\n\n    public final void setCanCompress(boolean canCompress) {\n        this.canCompress = canCompress;\n    }\n\n    public final double getCollisions() {\n        return collisions;\n    }\n\n    public final void setCollisions(final double collisions) {\n        this.collisions = collisions;\n    }\n\n    public final int getTXQueueLen() {\n        return txqueuelen;\n    }\n\n    public final void setTXQueueLen(final int txqueuelen) {\n        this.txqueuelen = txqueuelen;\n    }\n\n    /**\n     * Utility method for printing out the properties\n     */\n    public String toString() {\n\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"IFNAME [name=\").append(name);\n        buf.append(\",ipv4=\").append(ipv4);\n        buf.append(\",bcast4=\").append(bcastipv4);\n        buf.append(\",mask4=\").append(maskipv4);\n        buf.append(\",mtu=\").append(mtu);\n        buf.append(\",rx_packets=\").append(rxPackets);\n        buf.append(\",tx_packets=\").append(txPackets);\n        buf.append(\"]\");\n        return buf.toString();\n    }\n\n\n} // end of class InterfaceStatistics\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/dev/InterfaceStatisticsStatic.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.dev;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\nimport java.util.LinkedList;\n\n/**\n * @author Ciprian Dobre\n */\npublic class InterfaceStatisticsStatic extends Statistics {\n\n    /********* Types of interface encapsulations *****************/\n\n    public static final byte TYPE_ETHERNET = 0;\n    public static final byte TYPE_FIBER = 1;\n\n    public static final byte PORT_TP = 1;\n    public static final byte PORT_AUI = 2;\n    public static final byte PORT_BNC = 4;\n    public static final byte PORT_MII = 8;\n    public static final byte PORT_FIBRE = 16;\n\n    public static final byte SUPPORTED_10BaseT_Half = 1;\n    public static final byte SUPPORTED_10BaseT_Full = 2;\n    public static final byte SUPPORTED_100BaseT_Half = 4;\n    public static final byte SUPPORTED_100BaseT_Full = 8;\n    public static final byte SUPPORTED_1000BaseT_Half = 16;\n    public static final byte SUPPORTED_1000BaseT_Full = 32;\n\n    public static final byte LINK_HALF = 0;\n    public static final byte LINK_DUPLEX = 1;\n\n\n    /**\n     * The name of the interface\n     */\n    protected final String name;\n\n    /**\n     * The encapsulation type\n     */\n    protected byte encap = 0;\n\n    /**\n     * The hardware address of the interface\n     */\n    protected String hwAddr;\n\n    protected byte supportedPorts = -1; // -1 means error\n    protected byte supportedLinkModes = -1; // -1 means error\n    protected boolean supportsAutoNegotiation = false;\n\n    protected int maxSpeed = -1; // supported speed in Mb/s\n    protected byte duplex = -1; // -1 means unknown\n    protected byte port = -1; // -1 means unknown\n\n    /**\n     * The constructor - only the name is final\n     */\n    public InterfaceStatisticsStatic(final String name) {\n        super();\n        this.name = name;\n    }\n\n    /**\n     * Method used to retrieve the name of the interface\n     */\n    public final String getName() {\n        return name;\n    }\n\n    /**\n     * Getter for the type of encapsulation\n     */\n    public final byte getEncap() {\n        return encap;\n    }\n\n    /**\n     * Setter for the type of encapsulation for the network interface\n     */\n    public final void setEncap(final byte type) {\n        this.encap = type;\n    }\n\n    /**\n     * Getter for the type of encapsulation\n     */\n    public final String getEncapAsString() {\n        switch (encap) {\n            case TYPE_ETHERNET:\n                return \"Ethernet\";\n            case TYPE_FIBER:\n                return \"Fiber\";\n        }\n        return \"Unknown\";\n    }\n\n    /**\n     * Getter for the hardware address\n     */\n    public final String getHwAddr() {\n        return hwAddr;\n    }\n\n    /**\n     * Setter for the hardware address\n     */\n    public final void setHwAddr(final String hwAddr) {\n        this.hwAddr = hwAddr;\n    }\n\n    /**\n     * Utility method for printing out the properties\n     */\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"IFNAME [name=\").append(name);\n        buf.append(\",encap=\").append(getEncapAsString());\n        buf.append(\",hwaddr=\").append(hwAddr);\n        buf.append(\",supportedPort=\").append(supportedPorts);\n        buf.append(\",supportedLinkModes=\").append(supportedLinkModes);\n        buf.append(\",supportsAutoNeg=\").append(supportsAutoNegotiation);\n        buf.append(\",maxSpeed=\").append(maxSpeed);\n        buf.append(\",duplex=\").append(duplex);\n        buf.append(\",port=\").append(port);\n        buf.append(\"]\");\n        return buf.toString();\n    }\n\n    public byte getSupportedPorts() {\n        return supportedPorts;\n    }\n\n    public void setSupportedPorts(byte supportedPorts) {\n        if (this.supportedPorts < 0) this.supportedPorts = 0;\n        this.supportedPorts = (byte) (this.supportedPorts | supportedPorts);\n    }\n\n    private boolean flagSet(byte b, byte flag) {\n        return ((b & flag) == flag);\n    }\n\n    public String[] getSupportedPortsAsString() {\n\n        if (supportedPorts < 0) return new String[]{\"UNKNOWN\"};\n\n        final LinkedList<String> list = new LinkedList<String>();\n        if (flagSet(supportedPorts, PORT_TP)) list.addLast(\"TP\");\n        if (flagSet(supportedPorts, PORT_AUI)) list.addLast(\"AUI\");\n        if (flagSet(supportedPorts, PORT_BNC)) list.addLast(\"BNC\");\n        if (flagSet(supportedPorts, PORT_MII)) list.addLast(\"MII\");\n        if (flagSet(supportedPorts, PORT_FIBRE)) list.addLast(\"FIBRE\");\n\n        if (list.size() == 0) return new String[]{\"NONE\"};\n        return list.toArray(new String[0]);\n    }\n\n    public byte getSupportedLinkModes() {\n        return supportedLinkModes;\n    }\n\n    public void setSupportedLinkModes(byte supportedLinkModes) {\n        if (this.supportedLinkModes < 0) this.supportedLinkModes = 0;\n        this.supportedLinkModes = (byte) (this.supportedLinkModes | supportedLinkModes);\n    }\n\n    public String[] getSupportedLinkModesAsString() {\n        if (supportedLinkModes < 0) return new String[]{\"UNKNOWN\"};\n        final LinkedList<String> list = new LinkedList<String>();\n        if (flagSet(supportedLinkModes, SUPPORTED_10BaseT_Half)) list.add(\"10BaseT_Half\");\n        if (flagSet(supportedLinkModes, SUPPORTED_10BaseT_Full)) list.add(\"10BaseT_Full\");\n        if (flagSet(supportedLinkModes, SUPPORTED_100BaseT_Half)) list.add(\"100BaseT_Half\");\n        if (flagSet(supportedLinkModes, SUPPORTED_100BaseT_Full)) list.add(\"100BaseT_Full\");\n        if (flagSet(supportedLinkModes, SUPPORTED_1000BaseT_Half)) list.add(\"1000BaseT_Half\");\n        if (flagSet(supportedLinkModes, SUPPORTED_1000BaseT_Full)) list.add(\"1000BaseT_Full\");\n        if (list.size() == 0) return new String[]{\"NONE\"};\n        return list.toArray(new String[0]);\n    }\n\n    public boolean supportsAutoNegotiation() {\n        return supportsAutoNegotiation;\n    }\n\n    public void setSupportsAutoNegotiation(boolean supportsAutoNegotiation) {\n        this.supportsAutoNegotiation = supportsAutoNegotiation;\n    }\n\n    public int getMaxSpeed() {\n        return maxSpeed;\n    }\n\n    public void setMaxSpeed(int maxSpeed) {\n        this.maxSpeed = maxSpeed;\n    }\n\n    public String getMaxSpeedAsString() {\n        if (maxSpeed < 0)\n            return \"UNKNOWN\";\n        return maxSpeed + \" Mb/s\";\n    }\n\n    public byte getDuplex() {\n        return duplex;\n    }\n\n    public void setDuplex(byte duplex) {\n        this.duplex = duplex;\n    }\n\n    public byte getPort() {\n        return port;\n    }\n\n    public void setPort(byte port) {\n        this.port = port;\n    }\n\n} // end of class InterfaceStatisticsStatic\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/dev/MTUSet.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.dev;\n\nimport java.io.Serializable;\n\n/**\n * Wrapper for sending request to set a new value for the mtu\n *\n * @author Ciprian Dobre\n */\npublic class MTUSet implements Serializable {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    public String ifName;\n\n    public int mtu;\n\n} // end of class MTUSet\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/dev/TXQueueLenSet.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.dev;\n\nimport java.io.Serializable;\n\n/**\n * Wrapper for setting quelen...\n *\n * @author Ciprian Dobre\n */\npublic class TXQueueLenSet implements Serializable {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    public String ifName;\n\n    public int txqueuelen;\n\n} // end of class TXQueueLenSet\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/netstat/Connection.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.netstat;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\n/**\n * Informations about a given connection\n *\n * @author Ciprian Dobre\n */\npublic class Connection extends Statistics {\n\n    /**\n     * Types of connection protocol\n     ***/\n    public static final byte TCP_CONNECTION = 0;\n    public static final byte UDP_CONNECTION = 1;\n    public static final byte RAW_CONNECTION = 2;\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n    /**\n     * The protocol of the connection (can be tcp, udp or raw)\n     */\n    protected byte protocol;\n\n    /**\n     * The owner of the connection (username)\n     */\n    protected String powner;\n\n    /**\n     * The pid of the owner process\n     */\n    protected int pid;\n\n    /**\n     * The name of the program owning the connection\n     */\n    protected String pname;\n\n    /**\n     * Local port\n     */\n    protected int localPort;\n\n    /**\n     * Remote address of the connection\n     */\n    protected String remoteAddress;\n\n    /**\n     * Remote port\n     */\n    protected int remotePort;\n\n    /**\n     * Status of the connection\n     */\n    protected String status;\n\n    public Connection() {\n        super();\n    }\n\n    public final byte getProtocol() {\n        return protocol;\n    }\n\n    public final void setProtocol(final byte protocol) {\n        this.protocol = protocol;\n    }\n\n    public final String getProtocolAsString() {\n        switch (protocol) {\n            case TCP_CONNECTION:\n                return \"TCP\";\n            case UDP_CONNECTION:\n                return \"UDP\";\n            case RAW_CONNECTION:\n                return \"RAW\";\n        }\n        return \"UNKNOWN\";\n    }\n\n    public final String getPOwner() {\n        return powner;\n    }\n\n    public final void setPOwner(final String owner) {\n        this.powner = owner;\n    }\n\n    public final int getPID() {\n        return pid;\n    }\n\n    public final void setPID(final int pid) {\n        this.pid = pid;\n    }\n\n    public final String getPName() {\n        return pname;\n    }\n\n    public final void setPName(final String pname) {\n        this.pname = pname;\n    }\n\n    public final int getLocalPort() {\n        return localPort;\n    }\n\n    public final void setLocalPort(final int localPort) {\n        this.localPort = localPort;\n    }\n\n    public final String getRemoteAddress() {\n        return remoteAddress;\n    }\n\n    public final void setRemoteAddress(final String remoteAddress) {\n        this.remoteAddress = remoteAddress;\n    }\n\n    public final int getRemotePort() {\n        return remotePort;\n    }\n\n    public final void setRemotePort(final int remotePort) {\n        this.remotePort = remotePort;\n    }\n\n    public final String getStatus() {\n        return status;\n    }\n\n    public final void setStatus(final String status) {\n        this.status = status;\n    }\n\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"[Prot=\").append(getProtocolAsString());\n        buf.append(\",POwner=\").append(powner);\n        buf.append(\",PID=\").append(pid);\n        buf.append(\",PName=\").append(pname);\n        buf.append(\",LPort=\").append(localPort);\n        buf.append(\",RAddress=\").append(remoteAddress);\n        buf.append(\",RPort=\").append(remotePort);\n        buf.append(\",Status=\").append(status);\n        buf.append(\"]\");\n        return buf.toString();\n    }\n\n} // end of class Connection\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/netstat/Netstat.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.netstat;\n\nimport lia.util.net.copy.monitoring.lisa.net.PatternUtil;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.PrintStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Replacer for the netstat utility, by reading the /proc filesystem it can find out the\n * open connections of the system\n * From http://www.ussg.iu.edu/hypermail/linux/kernel/0409.1/2166.html :\n * It will first list all listening TCP sockets, and next list all established\n * TCP connections. A typical entry of /proc/net/tcp would look like this (split\n * up into 3 parts because of the length of the line):\n * <p>\n * 46: 010310AC:9C4C 030310AC:1770 01\n * | | | | | |--> connection state\n * | | | | |------> remote TCP port number\n * | | | |-------------> remote IPv4 address\n * | | |--------------------> local TCP port number\n * | |---------------------------> local IPv4 address\n * |----------------------------------> number of entry\n * <p>\n * 00000150:00000000 01:00000019 00000000\n * | | | | |--> number of unrecovered RTO timeouts\n * | | | |----------> number of jiffies until timer expires\n * | | |----------------> timer_active (see below)\n * | |----------------------> receive-queue\n * |-------------------------------> transmit-queue\n * <p>\n * 1000 0 54165785 4 cd1e6040 25 4 27 3 -1\n * | | | | | | | | | |--> slow start size threshold,\n * | | | | | | | | | or -1 if the treshold\n * | | | | | | | | | is >= 0xFFFF\n * | | | | | | | | |----> sending congestion window\n * | | | | | | | |-------> (ack.quick<<1)|ack.pingpong\n * | | | | | | |---------> Predicted tick of soft clock\n * | | | | | | (delayed ACK control data)\n * | | | | | |------------> retransmit timeout\n * | | | | |------------------> location of socket in memory\n * | | | |-----------------------> socket reference count\n * | | |-----------------------------> inode\n * | |----------------------------------> unanswered 0-window probes\n * |---------------------------------------------> uid\n *\n * @author Ciprian Dobre\n * @deprecated\n */\npublic class Netstat {\n\n    /**\n     * The stream to write output to\n     */\n    protected final PrintStream out;\n    protected final HashMap<String, String> pids = new HashMap<String, String>();\n    /**\n     * Possible values for states in /proc/net/tcp\n     */\n    final String states[] = {\"ESTBLSH\", \"SYNSENT\", \"SYNRECV\", \"FWAIT1\", \"FWAIT2\", \"TMEWAIT\",\n            \"CLOSED\", \"CLSWAIT\", \"LASTACK\", \"LISTEN\", \"CLOSING\", \"UNKNOWN\"\n    };\n    /**\n     * Pattern used when parsing through /proc/net/tcp\n     */\n    private final String netPattern = \"\\\\d+:\\\\s+([\\\\dA-F]+):([\\\\dA-F]+)\\\\s+([\\\\dA-F]+):([\\\\dA-F]+)\\\\s+([\\\\dA-F]+)\\\\s+\" +\n            \"[\\\\dA-F]+:[\\\\dA-F]+\\\\s+[\\\\dA-F]+:[\\\\dA-F]+\\\\s+[\\\\dA-F]+\\\\s+([\\\\d]+)\\\\s+[\\\\d]+\\\\s+([\\\\d]+)\";\n\n//\tprotected final HashMap<String, Integer> inodes; \n\n    /**\n     * The constructor\n     *\n     * @param out        The stream to write output to\n     */\n    public Netstat(final PrintStream out) {\n        this.out = out;\n//\t\tinodes = new HashMap<String, Integer>();\n    }\n\n    public static void main(String args[]) {\n        System.out.println(\"Start\");\n        Netstat n = new Netstat(System.out);\n        List<Connection> c = n.getConnections();\n        for (Connection conn : c) {\n            System.out.println(conn);\n        }\n        System.out.println(\"end\");\n    }\n\n    /**\n     * Utility method that converts an address from a hexa representation as founded in /proc to String representation\n     */\n    private final String getAddress(final String hexa) {\n        try {\n            // first let's convert the address to Integer\n            final long v = Long.parseLong(hexa, 16);\n            // because in /proc the order is little endian and java uses big endian order we also need to invert the order\n            final long adr = (v >>> 24) | (v << 24) |\n                    ((v << 8) & 0x00FF0000) | ((v >> 8) & 0x0000FF00);\n            // and now it's time to output the result\n            return ((adr >> 24) & 0xff) + \".\" + ((adr >> 16) & 0xff) + \".\" + ((adr >> 8) & 0xff) + \".\" + (adr & 0xff);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            return \"0.0.0.0\";\n        }\n    }\n\n    private final int getInt16(final String hexa) {\n        try {\n            return Integer.parseInt(hexa, 16);\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            return -1;\n        }\n    }\n\n//\t/** Method used to question the open processes on the system */ \n//\tprivate void init() {\n//\t\t\n//\t\tinodes.clear();\n//\t\tfinal cmdExec exec = cmdExec.getInstance();\n//\t\tfinal File dir[] = new File(\"/proc\").listFiles();\n//\t\tif (dir == null || dir.length == 0) return;\n//\t\tfor (int i=0; i<dir.length; i++) {\n//\t\t\tif (!dir[i].canRead() || !dir[i].isDirectory()) continue; // not interested in regular files\n//\t\t\tfinal String pid = dir[i].getName();\n//\t\t\tif (pid == null || pid.length() == 0) continue;\n//\t\t\ttry {\n//\t\t\t\tLong.parseLong(pid);\n//\t\t\t} catch (Exception ex) {\n//\t\t\t\tcontinue; // also only interested in pid processes\n//\t\t\t}\n//\t\t\tfinal File fd = new File(\"/proc/\"+pid+\"/fd\");\n//\t\t\tif (!fd.exists() || !fd.canRead()) continue;\n//\t\t\tfinal File dir1[] = fd.listFiles();\n//\t\t\tif (dir1 == null || dir1.length == 0) continue;\n//\t\t\tfor (int j=0; j<dir1.length; j++) {\n//\t\t\t\tif (!dir1[j].canRead()) continue;\n//\t\t\t\tfinal String id = dir1[j].getName();\n//\t\t\t\tif (id == null || id.length() == 0) continue;\n//\t\t\t\ttry {\n//\t\t\t\t\tLong.parseLong(id);\n//\t\t\t\t} catch (Exception ex) {\n//\t\t\t\t\tcontinue; // also only interested in pid processes\n//\t\t\t\t}\n//\t\t\t\t// let's check the inode and the type of file \n//\t\t\t\tfinal String ret = exec.executeCommandReality(getStatPath()+\"stat -L -c=%i-%F \"+dir1[j].getAbsolutePath(), null);\n//\t\t\t\t\n//\t\t\t\tSystem.out.println(ret);\n//\t\t\t\t\n//\t\t\t\tif (exec.isError() || ret == null || ret.length() == 0) {\n//\t\t\t\t\tcontinue;\n//\t\t\t\t}\n//\t\t\t\tif (!ret.startsWith(\"=\")) continue;\n//\t\t\t\tfinal String type = ret.substring(ret.indexOf(\"-\")+1, ret.length()-1);\n//\t\t\t\tif (!type.equals(\"socket\")) continue;\n//\t\t\t\t// check the uid\n//\t\t\t\tinodes.put(ret.substring(1, ret.indexOf(\"-\")).trim(), Integer.parseInt(pid));\n//\t\t\t}\n//\t\t}\n//\t\t\n//\t}\n\n    /**\n     * Returns the path to stat utility as declared by the user\n     */\n    private final String getStatPath() {\n        String path = System.getProperty(\"net.stat.path\", \"/usr/bin/\"); // if no properties than just use sbin\n        path = path.trim();\n        if (!path.endsWith(\"/\")) path = path + \"/\"; // make sure that path always ends in \"/\";\n        return path;\n    }\n\n    /**\n     * Utility method used to obtain the name of an user based on an uid\n     */\n    private final String getPUID(final String uid) {\n        if (pids.containsKey(uid))\n            return pids.get(uid);\n        final String pat = \"([\\\\S&&[^:]]+):[\\\\S&&[^:]]+:\" + uid + \":\";\n        final Pattern pattern = PatternUtil.getPattern(\"uid_\" + uid, pat);\n        try {\n            BufferedReader in = new BufferedReader(new FileReader(\"/etc/passwd\"));\n            String line;\n            while ((line = in.readLine()) != null) {\n                final Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    final String puid = matcher.group(1);\n                    pids.put(uid, puid);\n                    return puid;\n                }\n            }\n            in.close();\n        } catch (Throwable t) {\n        }\n        pids.put(uid, \"UNKNOWN\");\n        return \"UNKNOWN\";\n    }\n\n    private final String getPName(final int pid) {\n        final String pat = \"Name:\\\\s*(\\\\S+)\";\n        final Pattern pattern = PatternUtil.getPattern(\"pname\", pat);\n        try {\n            BufferedReader in = new BufferedReader(new FileReader(\"/proc/\" + pid + \"/status\"));\n            String line;\n            while ((line = in.readLine()) != null) {\n                final Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    return matcher.group(1);\n                }\n            }\n            in.close();\n        } catch (Throwable t) {\n        }\n        return \"UNKNOWN\";\n    }\n\n    /**\n     * Method used to question for the connections currently openned\n     *\n     * @return The list of connections (as Connection objects)\n     */\n    public List<Connection> getConnections() {\n\n        final ArrayList<Connection> net = new ArrayList<Connection>();\n\n//\t\tinit();\n\n        // read from /proc/net/tcp the list of currently openned socket connections\n        try {\n            BufferedReader in = new BufferedReader(new FileReader(\"/proc/net/tcp\"));\n            String line;\n            while ((line = in.readLine()) != null) {\n                Pattern pattern = PatternUtil.getPattern(\"/proc/net/tcp\", netPattern);\n                Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    final Connection c = new Connection();\n                    c.setProtocol(Connection.TCP_CONNECTION);\n                    net.add(c);\n                    final String localPortHexa = matcher.group(2);\n                    final String remoteAddressHexa = matcher.group(3);\n                    final String remotePortHexa = matcher.group(4);\n                    final String statusHexa = matcher.group(5);\n                    final String uid = matcher.group(6);\n                    final String inode = matcher.group(7);\n                    c.setLocalPort(getInt16(localPortHexa));\n                    c.setRemoteAddress(getAddress(remoteAddressHexa));\n                    c.setRemotePort(getInt16(remotePortHexa));\n                    try {\n                        c.setStatus(states[Integer.parseInt(statusHexa, 16) - 1]);\n                    } catch (Exception ex) {\n                        c.setStatus(states[11]); // unknwon\n                    }\n//\t\t\t\tif (inodes.containsKey(inode)) {\n//\t\t\t\t\tc.setPID(inodes.get(inode));\n//\t\t\t\t\tc.setPName(getPName(c.getPID()));\n//\t\t\t\t} else {\n                    c.setPID(-1); // unknown\n                    c.setPName(\"UNKNOWN\");\n//\t\t\t\t}\n                    c.setPOwner(getPUID(uid));\n                }\n            }\n            in.close();\n        } catch (Throwable t) {\n        }\n\n        // read from /proc/net/udp the list of currently openned socket connections\n        try {\n            BufferedReader in = new BufferedReader(new FileReader(\"/proc/net/udp\"));\n            String line;\n            while ((line = in.readLine()) != null) {\n                Pattern pattern = PatternUtil.getPattern(\"/proc/net/tcp\", netPattern);\n                Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    final Connection c = new Connection();\n                    c.setProtocol(Connection.UDP_CONNECTION);\n                    net.add(c);\n                    final String localPortHexa = matcher.group(2);\n                    final String remoteAddressHexa = matcher.group(3);\n                    final String remotePortHexa = matcher.group(4);\n                    final String statusHexa = matcher.group(5);\n                    final String uid = matcher.group(6);\n                    final String inode = matcher.group(7);\n                    c.setLocalPort(getInt16(localPortHexa));\n                    c.setRemoteAddress(getAddress(remoteAddressHexa));\n                    c.setRemotePort(getInt16(remotePortHexa));\n                    try {\n                        c.setStatus(states[Integer.parseInt(statusHexa, 16) - 1]);\n                    } catch (Exception ex) {\n                        c.setStatus(states[11]); // unknwon\n                    }\n//\t\t\t\tif (inodes.containsKey(inode)) {\n//\t\t\t\t\tc.setPID(inodes.get(inode));\n//\t\t\t\t\tc.setPName(getPName(c.getPID()));\n//\t\t\t\t} else {\n                    c.setPID(-1); // unknown\n                    c.setPName(\"UNKNOWN\");\n//\t\t\t\t}\n                    c.setPOwner(getPUID(uid));\n                }\n            }\n            in.close();\n        } catch (Throwable t) {\n        }\n\n        // read from /proc/net/raw the list of currently openned socket connections\n        try {\n            BufferedReader in = new BufferedReader(new FileReader(\"/proc/net/raw\"));\n            String line;\n            while ((line = in.readLine()) != null) {\n                Pattern pattern = PatternUtil.getPattern(\"/proc/net/tcp\", netPattern);\n                Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    final Connection c = new Connection();\n                    c.setProtocol(Connection.RAW_CONNECTION);\n                    net.add(c);\n//\t\t\t\tfinal String localAddressHexa = matcher.group(1);\n                    final String localPortHexa = matcher.group(2);\n                    final String remoteAddressHexa = matcher.group(3);\n                    final String remotePortHexa = matcher.group(4);\n                    final String statusHexa = matcher.group(5);\n                    final String uid = matcher.group(6);\n                    final String inode = matcher.group(7);\n                    c.setLocalPort(getInt16(localPortHexa));\n                    c.setRemoteAddress(getAddress(remoteAddressHexa));\n                    c.setRemotePort(getInt16(remotePortHexa));\n                    try {\n                        c.setStatus(states[Integer.parseInt(statusHexa, 16) - 1]);\n                    } catch (Exception ex) {\n                        c.setStatus(states[11]); // unknwon\n                    }\n//\t\t\t\tif (inodes.containsKey(inode)) {\n//\t\t\t\t\tc.setPID(inodes.get(inode));\n//\t\t\t\t\tc.setPName(getPName(c.getPID()));\n//\t\t\t\t} else {\n                    c.setPID(-1); // unknown\n                    c.setPName(\"UNKNOWN\");\n//\t\t\t\t}\n                    c.setPOwner(getPUID(uid));\n                }\n            }\n            in.close();\n        } catch (Throwable t) {\n        }\n\n        return net;\n    }\n\n\n} // end of class Netstat\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/netstat/NetstatHandler.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.netstat;\n\nimport lia.util.net.copy.monitoring.lisa.cmdExec;\nimport lia.util.net.copy.monitoring.lisa.cmdExec.CommandResult;\nimport lia.util.net.copy.monitoring.lisa.net.PatternUtil;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.PrintStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.logging.Logger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Handler task for monitoring the current connections\n *\n * @author Ciprian Dobre\n */\npublic class NetstatHandler {\n\n    /**\n     * The stream to write output to\n     */\n    protected final PrintStream out;\n\n    /**\n     * Utility object used for running different commands\n     */\n    protected final cmdExec exec;\n\n    /**\n     * Pattern used to parse the output of netstat utility\n     */\n    protected final String netstatPattern = \"\\\\S+\\\\s+\\\\d+\\\\s+\\\\d+\\\\s*(\\\\d*[\\\\.:]\\\\d*[\\\\.:]\\\\d*\\\\.*\\\\d*):(\\\\d+)\\\\s*\" +\n            \"(\\\\d*[\\\\.:]\\\\d*[\\\\.:]\\\\d*\\\\.*\\\\d*):([\\\\d\\\\*]+)\\\\s*([a-zA-Z]*)\\\\s*(\\\\d+)\\\\s*\\\\d+\\\\s*([\\\\d-]+)/*(\\\\S*)\";\n\n    protected final Logger logger;\n\n    protected boolean netstatPathSetup = false;\n    protected String netstatPath = null;\n\n    /**\n     * The constructor\n     *\n     * @param properties We need the properties of the module in order to interogate for paths\n     * @param out        The stream to write output to\n     */\n    public NetstatHandler(final PrintStream out, final Logger logger) {\n        this.logger = logger;\n        this.out = out;\n        exec = cmdExec.getInstance();\n    }\n\n    public static void main(String args[]) {\n\n//\t\tPattern p = Pattern.compile(\"(\\\\d*[\\\\.:]\\\\d*[\\\\.:]\\\\d*[\\\\.:]*\\\\d*):([\\\\d\\\\*]+)\");\n//\t\tMatcher m = p.matcher(\":::*\");\n//\t\tSystem.out.println(m.find());\n//\t\tif (true) return;\n\n        for (int i = 0; i < 10; i++) {\n            System.out.println(\"Start\");\n            NetstatHandler n = new NetstatHandler(System.out, null);\n            List<Connection> c = n.getConnections();\n            for (Connection conn : c) {\n                System.out.println(conn);\n            }\n            System.out.println(\"end\");\n        }\n    }\n\n    /**\n     * Returns the path to netstat utility as declared by the user\n     */\n    private synchronized final String getNetstatPath() {\n        String path = System.getProperty(\"net.netstat.path\", \"/bin,/sbin,/usr/bin,/usr/sbin\");\n        if (path != null && path.length() != 0)\n            path = path.replace(',', ':').trim();\n        return path;\n    }\n\n    /**\n     * Utility method used to obtain the name of an user based on an uid\n     */\n    private final String getPUID(final String uid) {\n        final String pat = \"([\\\\S&&[^:]]+):[\\\\S&&[^:]]+:\" + uid + \":\";\n        final Pattern pattern = PatternUtil.getPattern(\"uid_\" + uid, pat);\n        try {\n            BufferedReader reader = new BufferedReader(new FileReader(\"/etc/passwd\"));\n            String line;\n            while ((line = reader.readLine()) != null) {\n                final Matcher matcher = pattern.matcher(line);\n                if (matcher.find()) {\n                    return matcher.group(1);\n                }\n            }\n        } catch (Exception e) {\n        }\n        return \"UNKNOWN\";\n    }\n\n    /**\n     * Called in order to check if we should use netstat utility\n     *\n     * @return False if net.netstat.use is set to false\n     */\n    private final boolean shouldRunNetstatTool() {\n        String prop = System.getProperty(\"net.netstat.use\", null);\n        if (prop == null) return true;\n        try {\n            return Boolean.getBoolean(prop);\n        } catch (Throwable t) {\n        }\n        return true;\n    }\n\n    /**\n     * Called in order to check if we should try and parse from proc the current connections\n     *\n     * @return False if net.netstat_dev.use is set to false\n     */\n    private final boolean shouldRunNetstatDevTool() {\n        String prop = System.getProperty(\"net.netstat_dev.use\", null);\n        if (prop == null) return true;\n        try {\n            return Boolean.getBoolean(prop);\n        } catch (Throwable t) {\n        }\n        return true;\n    }\n\n    /**\n     * Method used to question for the connections currently openned\n     *\n     * @return The list of connections (as Connection objects)\n     */\n    public final List<Connection> getConnections() {\n\n        if (!shouldRunNetstatTool()) {\n            return null;\n        }\n        final ArrayList<Connection> net = new ArrayList<Connection>();\n\n        String netp = getNetstatPath();\n        CommandResult cmdRes = exec.executeCommandReality(\"netstat -antep\", null, 5 * 60 * 1000L, netp);\n        String ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null) {\n                out.println(ret);\n                out.println(\"Error running netstat\");\n            } else {\n                logger.info(ret);\n                logger.info(\"Error running netstat\");\n            }\n            return null;\n        }\n        final Pattern pattern = PatternUtil.getPattern(\"netstat\", netstatPattern);\n        String lines[] = ret.split(\"\\n\");\n        for (int i = 0; i < lines.length; i++) {\n            final Matcher matcher = pattern.matcher(lines[i]);\n            if (matcher.find()) {\n                final Connection c = new Connection();\n                net.add(c);\n                c.setProtocol(Connection.TCP_CONNECTION);\n                final String localPort = matcher.group(2);\n                final String remoteAddress = matcher.group(3);\n                final String remotePort = matcher.group(4);\n                final String state = matcher.group(5);\n                final String uid = matcher.group(6);\n                final String pid = matcher.group(7);\n                final String pname = matcher.group(8);\n                c.setPOwner(getPUID(uid));\n                try {\n                    c.setPID(Integer.parseInt(pid));\n                } catch (Exception ex) {\n                    c.setPID(-1);\n                }\n                c.setPName(pname);\n                try {\n                    c.setLocalPort(Integer.parseInt(localPort));\n                } catch (Exception ex) {\n                    c.setLocalPort(0);\n                }\n                c.setRemoteAddress(remoteAddress);\n                try {\n                    c.setRemotePort(Integer.parseInt(remotePort));\n                } catch (Exception ex) {\n                    c.setRemotePort(0);\n                }\n                c.setStatus(state);\n            }\n        }\n        cmdRes = exec.executeCommandReality(\"netstat -anuep\", null, 5 * 60 * 1000L, netp);\n        ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null) {\n                out.println(ret);\n                out.println(\"Error running netstat\");\n            } else {\n                logger.info(ret);\n                logger.info(\"Error running netstat\");\n            }\n            return net;\n        }\n        lines = ret.split(\"\\n\");\n        for (int i = 0; i < lines.length; i++) {\n            final Matcher matcher = pattern.matcher(lines[i]);\n            if (matcher.find()) {\n                final Connection c = new Connection();\n                net.add(c);\n                c.setProtocol(Connection.UDP_CONNECTION);\n                final String localPort = matcher.group(2);\n                final String remoteAddress = matcher.group(3);\n                final String remotePort = matcher.group(4);\n                final String state = matcher.group(5);\n                final String uid = matcher.group(6);\n                final String pid = matcher.group(7);\n                final String pname = matcher.group(8);\n                c.setPOwner(getPUID(uid));\n                try {\n                    c.setPID(Integer.parseInt(pid));\n                } catch (Exception ex) {\n                    c.setPID(-1);\n                }\n                c.setPName(pname);\n                try {\n                    c.setLocalPort(Integer.parseInt(localPort));\n                } catch (Exception ex) {\n                    c.setLocalPort(0);\n                }\n                c.setRemoteAddress(remoteAddress);\n                try {\n                    c.setRemotePort(Integer.parseInt(remotePort));\n                } catch (Exception ex) {\n                    c.setRemotePort(0);\n                }\n                c.setStatus(state);\n            }\n        }\n        cmdRes = exec.executeCommandReality(\"netstat -anwep\", null, 5 * 60 * 1000L, netp);\n        ret = cmdRes.getOutput();\n        if (cmdRes.failed() || ret == null || ret.length() == 0 || PatternUtil.getPattern(\"Unknown command\", null).matcher(ret).matches()) {\n            if (out != null) {\n                out.println(ret);\n                out.println(\"Error running netstat\");\n            } else {\n                logger.info(ret);\n                logger.info(\"Error running netstat\");\n            }\n            return net;\n        }\n        lines = ret.split(\"\\n\");\n        for (int i = 0; i < lines.length; i++) {\n            final Matcher matcher = pattern.matcher(lines[i]);\n            if (matcher.find()) {\n\n                final Connection c = new Connection();\n                net.add(c);\n                c.setProtocol(Connection.RAW_CONNECTION);\n                final String localPort = matcher.group(2);\n                final String remoteAddress = matcher.group(3);\n                final String remotePort = matcher.group(4);\n                final String state = matcher.group(5);\n                final String uid = matcher.group(6);\n                final String pid = matcher.group(7);\n                final String pname = matcher.group(8);\n                c.setPOwner(getPUID(uid));\n                try {\n                    c.setPID(Integer.parseInt(pid));\n                } catch (Exception ex) {\n                    c.setPID(-1);\n                }\n                c.setPName(pname);\n                try {\n                    c.setLocalPort(Integer.parseInt(localPort));\n                } catch (Exception ex) {\n                    c.setLocalPort(0);\n                }\n                c.setRemoteAddress(remoteAddress);\n                try {\n                    c.setRemotePort(Integer.parseInt(remotePort));\n                } catch (Exception ex) {\n                    c.setRemotePort(0);\n                }\n                c.setStatus(state);\n            }\n        }\n\n        return net;\n    }\n\n} // end of class NetstatHandler\n\n "
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/statistics/IPStatistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.statistics;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\nimport java.text.NumberFormat;\n\n/**\n * Statistics regarding the ip protocol suite\n *\n * @author Ciprian Dobre\n */\npublic class IPStatistics extends Statistics {\n\n    static final NumberFormat nf = NumberFormat.getInstance();\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    static {\n        nf.setMaximumFractionDigits(2);\n        nf.setMinimumFractionDigits(2);\n    }\n\n    /**\n     * Is ip forwarding enabled or disabled\n     */\n    protected boolean forwarding = false;\n    /**\n     * Default TTL value\n     */\n    protected long defaultTTL = 0L;\n    /**\n     * Total number of received packets\n     */\n    protected String inReceives = \"0\";\n    protected double inReceivesI = 0D;\n    /**\n     * Packets received with incorrect headers\n     */\n    protected String inHdrErrors = \"0\";\n    protected double inHdrErrorsI = 0D;\n    /**\n     * Packets received with invalid address field\n     */\n    protected String inAddrErrors = \"0\";\n    protected double inAddrErrorsI = 0D;\n    /**\n     * Number of forwarded datagrams\n     */\n    protected String forwDatagrams = \"0\";\n    protected double forwDatagramsI = 0D;\n    /**\n     * Number of packets with unknown protocol number\n     */\n    protected String inUnknownProtos = \"0\";\n    protected double inUnknownProtosI = 0D;\n    /**\n     * The number of discarded packets\n     */\n    protected String inDiscards = \"0\";\n    protected double inDiscardsI = 0D;\n    /**\n     * The number of packets delivered\n     */\n    protected String inDelivers = \"0\";\n    protected double inDeliversI = 0D;\n    /**\n     * Requests sent out\n     */\n    protected String outRequests = \"0\";\n    protected double outRequestsI = 0D;\n    /**\n     * Outgoing packets dropped\n     */\n    protected String outDiscards = \"0\";\n    protected double outDiscardsI = 0D;\n    /**\n     * Outgoing dropped packets because of missing route\n     */\n    protected String outNoRoutes = \"0\";\n    protected double outNoRoutesI = 0D;\n    /**\n     * Fragments dropped after time out\n     */\n    protected String reasmTimeout = \"0\";\n    protected double reasmTimeoutI = 0D;\n    /**\n     * Reassemblies requires\n     */\n    protected String reasmReqds = \"0\";\n    protected double reasmReqdsI = 0D;\n    /**\n     * Packets reassembled ok\n     */\n    protected String reasmOKs = \"0\";\n    protected double reasmOKsI = 0D;\n    /**\n     * Packets reassembled with failure\n     */\n    protected String reasmFails = \"0\";\n    protected double reasmFailsI = 0D;\n    /**\n     * Fragments received ok\n     */\n    protected String fragOKs = \"0\";\n    protected double fragOKsI = 0D;\n    /**\n     * Fragments failed\n     */\n    protected String fragFails = \"0\";\n    protected double fragFailsI = 0D;\n    /**\n     * Created fragments\n     */\n    protected String fragCreates = \"0\";\n    protected double fragCreatesI = 0D;\n\n    public IPStatistics() {\n        super();\n    }\n\n    public final boolean getForwarding() {\n        return forwarding;\n    }\n\n    public final void setForwarding(final boolean forwarding) {\n        this.forwarding = forwarding;\n    }\n\n    public final String getForwardingAsString() {\n        return \"Forwarding is \" + (forwarding ? \"enabled\" : \"disabled\");\n    }\n\n    public final long getDefaultTTL() {\n        return defaultTTL;\n    }\n\n    public final void setDefaultTTL(final long defaultTTL) {\n        this.defaultTTL = defaultTTL;\n    }\n\n    public final String getDefaultTTLAsString() {\n        return \"Default TTL is \" + defaultTTL;\n    }\n\n    public final void setInReceived(final String packetsReceived, final double packetsReceivedI) {\n        this.inReceives = packetsReceived;\n        this.inReceivesI = packetsReceivedI;\n    }\n\n    public final String getInReceived() {\n        return inReceives;\n    }\n\n    public final double getInReceivedI() {\n        return inReceivesI;\n    }\n\n    public final String getInReceivedAsString() {\n        return inReceives + \" total packets received [\" + nf.format(inReceivesI) + \"]\";\n    }\n\n    public final void setInHdrErrors(final String hdrErrors, final double hdrErrorsI) {\n        this.inHdrErrors = hdrErrors;\n        this.inHdrErrorsI = hdrErrorsI;\n    }\n\n    public final String getInHdrErrors() {\n        return inHdrErrors;\n    }\n\n    public final double getInHdrErrorsI() {\n        return inHdrErrorsI;\n    }\n\n    public final String getInHdrErrorsAsString() {\n        return inHdrErrors + \" with invalid headers\";\n    }\n\n    public final void setInAddrErrors(final String inAddrErrors, final double inAddrErrorsI) {\n        this.inAddrErrors = inAddrErrors;\n        this.inAddrErrorsI = inAddrErrorsI;\n    }\n\n    public final String getInAddrErrors() {\n        return inAddrErrors;\n    }\n\n    public final double getInAddrErrorsI() {\n        return inAddrErrorsI;\n    }\n\n    public final String getInAddrErrorsAsString() {\n        return inAddrErrors + \" with invalid addresses\";\n    }\n\n    public final void setForwDatagrams(final String forwDatagrams, final double forwDatagramsI) {\n        this.forwDatagrams = forwDatagrams;\n        this.forwDatagramsI = forwDatagramsI;\n    }\n\n    public final String getForwDatagrams() {\n        return forwDatagrams;\n    }\n\n    public final double getForwDatagramsI() {\n        return forwDatagramsI;\n    }\n\n    public final String getForwDatagramsAsString() {\n        return forwarding + \" datagrams forwarded\";\n    }\n\n    public final void setInUnknownProtos(final String inUnknownProtos, final double inUnknownProtosI) {\n        this.inUnknownProtos = inUnknownProtos;\n        this.inUnknownProtosI = inUnknownProtosI;\n    }\n\n    public final String getInUnknownProtos() {\n        return inUnknownProtos;\n    }\n\n    public final double getInUnknownProtosI() {\n        return inUnknownProtosI;\n    }\n\n    public final String getInUnknownProtosAsString() {\n        return inUnknownProtos + \" with unknown protocol\";\n    }\n\n    public final void setInDiscards(final String inDiscards, final double inDiscardsI) {\n        this.inDiscards = inDiscards;\n        this.inDiscardsI = inDiscardsI;\n    }\n\n    public final String getInDiscards() {\n        return inDiscards;\n    }\n\n    public final double getInDiscardsI() {\n        return inDiscardsI;\n    }\n\n    public final String getInDiscardsAsString() {\n        return inDiscards + \" incoming packets discarded\";\n    }\n\n    public final void setInDelivers(final String inDelivers, final double inDeliversI) {\n        this.inDelivers = inDelivers;\n        this.inDeliversI = inDeliversI;\n    }\n\n    public final String getInDelivers() {\n        return inDelivers;\n    }\n\n    public final double getInDeliversI() {\n        return inDeliversI;\n    }\n\n    public final String getInDeliversAsString() {\n        return inDelivers + \" incoming packets delivered\";\n    }\n\n    public final void setOutRequests(final String outRequests, final double outRequestsI) {\n        this.outRequests = outRequests;\n        this.outRequestsI = outRequestsI;\n    }\n\n    public final String getOutRequests() {\n        return outRequests;\n    }\n\n    public final double getOutRequestsI() {\n        return outRequestsI;\n    }\n\n    public final String getOutRequestsAsString() {\n        return outRequests + \" requests sent out\";\n    }\n\n    public final void setOutDiscards(final String outDiscards, final double outDiscardsI) {\n        this.outDiscards = outDiscards;\n        this.outDiscardsI = outDiscardsI;\n    }\n\n    public final String getOutDiscards() {\n        return outDiscards;\n    }\n\n    public final double getOutDiscardsI() {\n        return outDiscardsI;\n    }\n\n    public final String getOutDiscardsAsString() {\n        return outDiscards + \" outgoing packets dropped\";\n    }\n\n    public final void setOutNoRoutes(final String outNoRoutes, final double outNoRoutesI) {\n        this.outNoRoutes = outNoRoutes;\n        this.outNoRoutesI = outNoRoutesI;\n    }\n\n    public final String getOutNoRoutes() {\n        return outNoRoutes;\n    }\n\n    public final double getOutNoRoutesI() {\n        return outNoRoutesI;\n    }\n\n    public final String getOutNoRoutesAsString() {\n        return outNoRoutes + \" dropped because of missing route\";\n    }\n\n    public final void setReasmTimeout(final String reasmTimeout, final double reasmTimeoutI) {\n        this.reasmTimeout = reasmTimeout;\n        this.reasmTimeoutI = reasmTimeoutI;\n    }\n\n    public final String getReasmTimeout() {\n        return reasmTimeout;\n    }\n\n    public final double getReasmTimeoutI() {\n        return reasmTimeoutI;\n    }\n\n    public final String getReasmTimeoutAsString() {\n        return reasmTimeout + \" fragments dropped after timeout\";\n    }\n\n    public final void setReasmReqds(final String reasmReqds, final double reasmReqdsI) {\n        this.reasmReqds = reasmReqds;\n        this.reasmReqdsI = reasmReqdsI;\n    }\n\n    public final String getReasmReqds() {\n        return reasmReqds;\n    }\n\n    public final double getReasmReqdsI() {\n        return reasmReqdsI;\n    }\n\n    public final String getReasmReqdsAsString() {\n        return reasmReqds + \" reassemblies required\";\n    }\n\n    public final void setReasmOKs(final String reasmOKs, final double reasmOKsI) {\n        this.reasmOKs = reasmOKs;\n        this.reasmOKsI = reasmOKsI;\n    }\n\n    public final String getReasmOKs() {\n        return reasmOKs;\n    }\n\n    public final double getReasmOKsI() {\n        return reasmOKsI;\n    }\n\n    public final String getReasmOKsAsString() {\n        return reasmOKs + \" packets reassembled ok\";\n    }\n\n    public final void setReasmFails(final String reasmFails, final double reasmFailsI) {\n        this.reasmFails = reasmFails;\n        this.reasmFailsI = reasmFailsI;\n    }\n\n    public final String getReasmFails() {\n        return reasmFails;\n    }\n\n    public final double getReasmFailsI() {\n        return reasmFailsI;\n    }\n\n    public final String getReasmFailsAsString() {\n        return reasmFails + \" packet reassembles failed\";\n    }\n\n    public final void setFragOKs(final String fragOKs, final double fragOKsI) {\n        this.fragOKs = fragOKs;\n        this.fragOKsI = fragOKsI;\n    }\n\n    public final String getFragOKs() {\n        return fragOKs;\n    }\n\n    public final double getFragOKsI() {\n        return fragOKsI;\n    }\n\n    public final String getFragOKsAsString() {\n        return fragOKs + \" fragments received ok\";\n    }\n\n    public final void setFragFails(final String fragFails, final double fragFailsI) {\n        this.fragFails = fragFails;\n        this.fragFailsI = fragFailsI;\n    }\n\n    public final String getFragFails() {\n        return fragFails;\n    }\n\n    public final double getFragFailsI() {\n        return fragFailsI;\n    }\n\n    public final String getFragFailsAsString() {\n        return fragFails + \" fragments failed\";\n    }\n\n    public final void setFragCreates(final String fragCreates, final double fragCreatesI) {\n        this.fragCreates = fragCreates;\n        this.fragCreatesI = fragCreatesI;\n    }\n\n    public final String getFragCreates() {\n        return fragCreates;\n    }\n\n    public final double getFragCreatesI() {\n        return fragCreatesI;\n    }\n\n    public final String getFragCreatesAsString() {\n        return fragCreates + \" fragments created\";\n    }\n\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"IP Statistics:\\n\");\n        buf.append(getForwardingAsString()).append(\"\\n\");\n        buf.append(getDefaultTTLAsString()).append(\"\\n\");\n        buf.append(getInReceivedAsString()).append(\"\\n\");\n        buf.append(getInHdrErrorsAsString()).append(\"\\n\");\n        buf.append(getInAddrErrorsAsString()).append(\"\\n\");\n        buf.append(getForwDatagramsAsString()).append(\"\\n\");\n        buf.append(getInUnknownProtosAsString()).append(\"\\n\");\n        buf.append(getInDiscardsAsString()).append(\"\\n\");\n        buf.append(getInDeliversAsString()).append(\"\\n\");\n        buf.append(getOutRequestsAsString()).append(\"\\n\");\n        buf.append(getOutDiscardsAsString()).append(\"\\n\");\n        buf.append(getOutNoRoutesAsString()).append(\"\\n\");\n        buf.append(getReasmTimeoutAsString()).append(\"\\n\");\n        buf.append(getReasmReqdsAsString()).append(\"\\n\");\n        buf.append(getReasmOKsAsString()).append(\"\\n\");\n        buf.append(getReasmFailsAsString()).append(\"\\n\");\n        buf.append(getFragOKsAsString()).append(\"\\n\");\n        buf.append(getFragFailsAsString()).append(\"\\n\");\n        buf.append(getFragCreatesAsString()).append(\"\\n\");\n        return buf.toString();\n    }\n\n} // end of class IPStatistics\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/statistics/StatisticsHandler.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.statistics;\n\nimport java.io.*;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.text.NumberFormat;\nimport java.util.HashMap;\nimport java.util.NoSuchElementException;\nimport java.util.StringTokenizer;\nimport java.util.TreeMap;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Statistics monitoring task (based on statistics of Andi Kleen)\n * Handler for statistics based on /proc/net/snmp and /proc/net/netstat\n *\n * @author Ciprian Dobre\n */\npublic class StatisticsHandler {\n\n    final static NumberFormat nf = NumberFormat.getInstance();\n\n    static {\n        nf.setMaximumFractionDigits(4);\n        nf.setMinimumFractionDigits(4);\n    }\n\n    /**\n     * The stream to write output to\n     */\n    protected final PrintStream out;\n    protected final Logger logger;\n    private final HashMap<String, TreeMap<Long, String>> lastValues = new HashMap<String, TreeMap<Long, String>>();\n    /**\n     * The current obtained results...\n     */\n\n    private IPStatistics ipStatistics = null;\n    private TCPStatistics tcpStatistics = null;\n    private UDPStatistics udpStatistics = null;\n    private TCPExtStatistics tcpExtStatistics = null;\n    /**\n     * is this a 64 bits arch ?\n     */\n    private boolean is64BitArch = false;\n\n    /**\n     * The constructor\n     *\n     * @param out        The stream to write output to\n     */\n    public StatisticsHandler(final PrintStream out, final Logger logger) {\n        this.out = out;\n        this.logger = logger;\n    }\n\n    public static void main(String args[]) {\n\n        StatisticsHandler h = new StatisticsHandler(System.out, null);\n        NumberFormat nf = NumberFormat.getInstance();\n        nf.setMaximumFractionDigits(2);\n        nf.setMinimumFractionDigits(2);\n\n        double d = h.getInstantValue(\"test\", 1000, \"105395052\");\n        d = h.getInstantValue(\"test\", 6000, \"105395986\");\n        System.out.println(nf.format(d));\n    }\n\n    /**\n     * Auxiliary method that returns the value of a string\n     */\n    private final int getValueAsInt(final String val) {\n        try {\n            return Integer.parseInt(val.trim());\n        } catch (Exception ex) {\n            return 0;\n        }\n    }\n\n    /**\n     * Auxiliary method that returns the value of a string\n     */\n    private final long getValueAsLong(final String val) {\n        try {\n            return Long.parseLong(val.trim());\n        } catch (Exception ex) {\n            return 0L;\n        }\n    }\n\n    public final double getInstantValue(String key, long time, String newVal) {\n\n        TreeMap<Long, String> h = null;\n        if (!lastValues.containsKey(key)) {\n            h = new TreeMap<Long, String>();\n            lastValues.put(key, h);\n        } else\n            h = lastValues.get(key);\n        if (h.size() == 0) {\n            h.put(time, newVal);\n            return 0D;\n        }\n        if (h.size() == 2)\n            h.remove(h.firstKey());\n        h.put(time, newVal);\n        long first = h.firstKey();\n        long last = h.lastKey();\n        String s1 = h.get(first);\n        String s2 = h.get(last);\n        double d = 0D;\n        try {\n            d = Double.parseDouble(diffWithOverflowCheck(s2, s1));\n        } catch (Throwable t) {\n            d = 0D;\n        }\n        d = d / ((last - first) / 1000D);\n        return d;\n\n\n//\t\tTreeMap<Long, String> h = null;\n//\t\tif (!lastValues.containsKey(key)) {\n//\t\t\th = new TreeMap<Long, String>();\n//\t\t\tlastValues.put(key, h);\n//\t\t} else\n//\t\t\th = lastValues.get(key);\n//\t\th.put(time, newVal);\n//\t\tif (h.size() == 1) return 0D;\n//\t\tlong first = h.firstKey();\n//\t\tlong last = h.lastKey();\n//\t\tString s1 = h.get(first);\n//\t\tString s2 = h.get(last);\n//\t\tdouble d = 0D;\n//\t\ttry {\n//\t\t\td = Double.parseDouble(diffWithOverflowCheck(s2, s1));\n//\t\t} catch (Throwable t) {\n//\t\t\td = 0D;\n//\t\t}\n//\t\td = d / ((last - first) / 1000D);\n//\t\tlong diffTime = 60 * 1000;\n//\t\tif (properties != null)\n//\t\t\tdiffTime = properties.geti(\"stat.interval\", 60, \"The interval to consider when computing the instant values\") * 1000;\n//\t\tif (diffTime <= 0) diffTime = 60 * 1000;\n//\t\tif ((last - first) < diffTime) {\n//\t\t\th.clear();\n//\t\t\th.put(first, s1);\n//\t\t\th.put(last, s2);\n//\t\t} else {\n//\t\t\tlong inner = last - diffTime;\n//\t\t\tString ss = diffWithOverflowCheck(s2, s1);\n//\t\t\tdouble dd = 0D;\n//\t\t\ttry { dd = Double.parseDouble(ss); } catch (Throwable t) { dd = 0D; }\n//\t\t\tdd = dd * (inner - first) / (last - first);\n//\t\t\th.clear();\n//\t\t\th.put(inner, addWithOverflowCheck(s1, \"\"+dd));\n//\t\t\th.put(last, s2);\n//\t\t}\n//\t\treturn d;\n    }\n\n    /**\n     * Auxiliary method\n     */\n    private final boolean getBooleanOf(final String val) {\n        return getValueAsInt(val) == 2 ? true : false;\n    }\n\n    /**\n     * Method used for parsing the values for IP\n     */\n    private final IPStatistics parseIPTable(final String headerLine, final String valuesLine, final IPStatistics ipstat) {\n\n        final IPStatistics stat = (ipstat != null) ? ipstat : new IPStatistics();\n        final StringTokenizer tok = new StringTokenizer(headerLine);\n        final StringTokenizer valTok = new StringTokenizer(valuesLine);\n        String el;\n        try {\n            while ((el = tok.nextToken(\" \\t\\n\")) != null) {\n                String valEl = valTok.nextToken(\" \\t\\n\");\n                if (valEl == null) break;\n                if (el.equals(\"Forwarding\")) { // ip forwarding\n                    stat.setForwarding(getBooleanOf(valEl));\n                    continue; // advance to the next token\n                }\n                if (el.equals(\"DefaultTTL\")) { // default ttl value\n                    stat.setDefaultTTL(getValueAsLong(valEl));\n                    continue;\n                }\n                if (el.equals(\"InReceives\")) { // in received packets\n                    stat.setInReceived(valEl, getInstantValue(\"InReceives\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InHdrErrors\")) { // in packets with header errors\n                    stat.setInHdrErrors(valEl, getInstantValue(\"InHdrErrors\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InAddrErrors\")) { // in packets with incorrect address field\n                    stat.setInAddrErrors(valEl, getInstantValue(\"InAddrErrors\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ForwDatagrams\")) { // number of forwarded datagrams\n                    stat.setForwDatagrams(valEl, getInstantValue(\"ForwDatagrams\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InUnknownProtos\")) { // number of packets with uknown protocol\n                    stat.setInUnknownProtos(valEl, getInstantValue(\"InUnknownProtos\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InDiscards\")) { // number of discarded packets\n                    stat.setInDiscards(valEl, getInstantValue(\"InDiscards\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InDelivers\")) { // number of delivered packets\n                    stat.setInDelivers(valEl, getInstantValue(\"InDelivers\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutRequests\")) { // number of requests sent out\n                    stat.setOutRequests(valEl, getInstantValue(\"OutRequest\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutDiscards\")) { // number of outgoing dropped packets\n                    stat.setOutDiscards(valEl, getInstantValue(\"OutDiscards\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutNoRoutes\")) { // number of dropped because of no route  found\n                    stat.setOutNoRoutes(valEl, getInstantValue(\"OutNoRoutes\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ReasmTimeout\")) { // number of fragments dropped after timeout\n                    stat.setReasmTimeout(valEl, getInstantValue(\"ReasmTimeout\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ReasmReqds\")) { // reassemblies required\n                    stat.setReasmReqds(valEl, getInstantValue(\"ReasmReqds\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ReasmOKs\")) { // reassembled ok\n                    stat.setReasmOKs(valEl, getInstantValue(\"ReasmsOKs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ReasmFails\")) { // failed reassembled\n                    stat.setReasmFails(valEl, getInstantValue(\"ReasmFails\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"FragOKs\")) { // fragments received ok\n                    stat.setFragOKs(valEl, getInstantValue(\"FragOKs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"FragFails\")) { // fragments failed\n                    stat.setFragFails(valEl, getInstantValue(\"FragFails\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"FragCreates\")) { // created fragments\n                    stat.setFragCreates(valEl, getInstantValue(\"FragCreates\", stat.getTime(), valEl));\n                }\n            }\n        } catch (NoSuchElementException nse) { // done parsing\n        }\n        return stat;\n    }\n\n    /**\n     * Method used for parsing the statictical values for TCP stack\n     */\n    private final TCPStatistics parseTCPTable(final String headerLine, final String valuesLine, final TCPStatistics tcpstat) {\n        final TCPStatistics stat = (tcpstat != null) ? tcpstat : new TCPStatistics();\n        final StringTokenizer tok = new StringTokenizer(headerLine);\n        final StringTokenizer valTok = new StringTokenizer(valuesLine);\n        String el;\n        try {\n            while ((el = tok.nextToken(\" \\t\\n\")) != null) {\n                String valEl = valTok.nextToken(\" \\t\\n\");\n                if (valEl == null) break;\n                if (el.equals(\"RtoMin\")) { // minimum retransmission time\n                    stat.setRToMin(getValueAsLong(valEl));\n                    continue; // advance to the next token\n                }\n                if (el.equals(\"RtoMax\")) { // maximum retransmission time\n                    stat.setRToMax(getValueAsLong(valEl));\n                    continue;\n                }\n                if (el.equals(\"ActiveOpens\")) { // active connections openned\n                    stat.setActiveOpens(valEl, getInstantValue(\"ActiveOpens\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"PassiveOpens\")) { // passive connections openned\n                    stat.setPassiveOpens(valEl, getInstantValue(\"PassiveOpens\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"AttemptFails\")) { // failed connection attempts\n                    stat.setAttemptFails(valEl, getInstantValue(\"AttemptFails\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"EstabResets\")) { // connection resets received\n                    stat.setEstabResets(valEl, getInstantValue(\"EstabResets\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"CurrEstab\")) { // connections currently established\n                    stat.setCurrEstab(getValueAsLong(valEl));\n                    continue;\n                }\n                if (el.equals(\"InSegs\")) { // received segments\n                    stat.setInSegs(valEl, getInstantValue(\"InSegs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutSegs\")) { // segments sent out\n                    stat.setOutSegs(valEl, getInstantValue(\"OutSegs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"RetransSegs\")) { // retransmitted segments\n                    stat.setRetransSegs(valEl, getInstantValue(\"RetransSegs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InErrs\")) { // bad segments receied\n                    stat.setInErrs(valEl, getInstantValue(\"InErrs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutRsts\")) { // resets sent\n                    stat.setOutRsts(valEl, getInstantValue(\"OutRsts\", stat.getTime(), valEl));\n                }\n            }\n        } catch (NoSuchElementException nse) { // done parsing\n        }\n        return stat;\n    }\n\n    /**\n     * Method used for parsing the statictical values for UDP stack\n     */\n    private final UDPStatistics parseUDPTable(final String headerLine, final String valuesLine, final UDPStatistics udpstat) {\n        final UDPStatistics stat = (udpstat != null) ? udpstat : new UDPStatistics();\n        final StringTokenizer tok = new StringTokenizer(headerLine);\n        final StringTokenizer valTok = new StringTokenizer(valuesLine);\n        String el;\n        try {\n            while ((el = tok.nextToken(\" \\t\\n\")) != null) {\n                String valEl = valTok.nextToken(\" \\t\\n\");\n                if (valEl == null) break;\n                if (el.equals(\"InDatagrams\")) { // datagrams received\n                    stat.setInDatagrams(valEl, getInstantValue(\"InDatagrams\", stat.getTime(), valEl));\n                    continue; // advance to the next token\n                }\n                if (el.equals(\"NoPorts\")) { // datagrams with no correct ports\n                    stat.setNoPorts(valEl, getInstantValue(\"NoPorts\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"InErrors\")) { // error datagrams\n                    stat.setInErrors(valEl, getInstantValue(\"InErrors\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OutDatagrams\")) { // sent datagrams\n                    stat.setOutDatagrams(valEl, getInstantValue(\"OutDatagrams\", stat.getTime(), valEl));\n                }\n            }\n        } catch (NoSuchElementException nse) { // done parsing\n        }\n        return stat;\n    }\n\n    /**\n     * Method used for parsing the extended statistical values for TCP stack\n     */\n    private final TCPExtStatistics parseExtendedTCPTable(final String headerLine, final String valuesLine, final TCPExtStatistics tcpstat) {\n        final TCPExtStatistics stat = (tcpstat != null) ? tcpstat : new TCPExtStatistics();\n        final StringTokenizer tok = new StringTokenizer(headerLine);\n        final StringTokenizer valTok = new StringTokenizer(valuesLine);\n        String el;\n        try {\n            while ((el = tok.nextToken(\" \\t\\n\")) != null) {\n                String valEl = valTok.nextToken(\" \\t\\n\");\n                if (valEl == null) break;\n                if (el.equals(\"SyncookiesSent\")) { // syncookies sent\n                    stat.setSyncookiesSent(valEl, getInstantValue(\"SyncookiesSent\", stat.getTime(), valEl));\n                    continue; // advance to the next token\n                }\n                if (el.equals(\"SyncookiesRecv\")) { // syncookies received\n                    stat.setSyncookiesRecv(valEl, getInstantValue(\"SyncookiesRecv\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"SyncookiesFailed\")) { // syncookies failed\n                    stat.setSyncookiesFailed(valEl, getInstantValue(\"SyncookiesFailed\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"EmbryonicRsts\")) { // embryonic resets\n                    stat.setEmbryonicRsts(valEl, getInstantValue(\"EmbryonicRsts\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"PruneCalled\")) { // packets prunned because of buffer overflow\n                    stat.setPruneCalled(valEl, getInstantValue(\"PruneCalled\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"RcvPruned\")) { // packets prunned from received queue\n                    stat.setRcvPruned(valEl, getInstantValue(\"RcvPruned\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"OfoPruned\")) { // packets prunned from out-of-order queue - overfow\n                    stat.setOfoPruned(valEl, getInstantValue(\"OfoPruned\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TW\")) {\n                    stat.setTW(valEl, getInstantValue(\"TW\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TWRecycled\")) {\n                    stat.setTWRecycled(valEl, getInstantValue(\"TWRecycled\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TWKilled\")) {\n                    stat.setTWKilled(valEl, getInstantValue(\"TWKilled\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"PAWSPassive\")) {\n                    stat.setPAWSPassive(valEl, getInstantValue(\"PAWSPassive\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"PAWSActive\")) {\n                    stat.setPAWSActive(valEl, getInstantValue(\"PAWSActive\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"PAWSEstab\")) {\n                    stat.setPAWSEstab(valEl, getInstantValue(\"PAWEstab\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"DelayedACKs\")) {\n                    stat.setDelayedACKs(valEl, getInstantValue(\"DelayedACKs\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"DelayedACKLocked\")) {\n                    stat.setDelayedACKLocked(valEl, getInstantValue(\"DelayedACKLocked\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"DelayedACKLost\")) {\n                    stat.setDelayedACKLost(valEl, getInstantValue(\"DelayedACKLost\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ListenOverflows\")) {\n                    stat.setListenOverflows(valEl, getInstantValue(\"ListenOverflows\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"ListenDrops\")) {\n                    stat.setListenDrops(valEl, getInstantValue(\"ListenDrops\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPPrequeued\")) {\n                    stat.setTCPPrequeued(valEl, getInstantValue(\"TCPPrequeued\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDirectCopyFromBacklog\")) {\n                    stat.setTCPDirectCopyFromBacklog(valEl, getInstantValue(\"TCPDirectCopyFromBacklog\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDirectCopyFromPrequeue\")) {\n                    stat.setTCPDirectCopyFromPrequeue(valEl, getInstantValue(\"TCPDirectCopyFromPrequeue\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPPrequeueDropped\")) {\n                    stat.setTCPPrequeueDropped(valEl, getInstantValue(\"TCPPrequeueDropped\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPHPHits\")) {\n                    stat.setTCPHPHits(valEl, getInstantValue(\"TCPHPHits\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPHPHitsToUser\")) {\n                    stat.setTCPHPHitsToUser(valEl, getInstantValue(\"TCPHPHitsToUser\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"SockMallocOOM\")) {\n                    stat.setSockMallocOOM(valEl, getInstantValue(\"SockMallocOOM\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPPureAcks\")) {\n                    stat.setTCPPureAcks(valEl, getInstantValue(\"TCPPureAcks\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPHPAcks\")) {\n                    stat.setTCPHPAcks(valEl, getInstantValue(\"TCPHPAcks\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPRenoRecovery\")) {\n                    stat.setTCPRenoRecovery(valEl, getInstantValue(\"TCPRenoRecovery\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSackRecovery\")) {\n                    stat.setTCPSackRecovery(valEl, getInstantValue(\"TCPSackRecovery\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSACKReneging\")) {\n                    stat.setTCPSACKReneging(valEl, getInstantValue(\"TCPSACKReneging\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPFACKReorder\")) {\n                    stat.setTCPFACKReorder(valEl, getInstantValue(\"TCPFACKReorder\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSACKReorder\")) {\n                    stat.setTCPSACKReorder(valEl, getInstantValue(\"TCPSACKReorder\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPRenoReorder\")) {\n                    stat.setTCPRenoReorder(valEl, getInstantValue(\"TCPRenoReorder\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPTSReorder\")) {\n                    stat.setTCPTSReorder(valEl, getInstantValue(\"TCPTSReorder\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPFullUndo\")) {\n                    stat.setTCPFullUndo(valEl, getInstantValue(\"TCPFullUndo\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPPartialUndo\")) {\n                    stat.setTCPPartialUndo(valEl, getInstantValue(\"TCPPartialUndo\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDSACKUndo\")) {\n                    stat.setTCPDSACKUndo(valEl, getInstantValue(\"TCPDSACKUndo\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPLossUndo\")) {\n                    stat.setTCPLossUndo(valEl, getInstantValue(\"TCPLossUndo\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPLoss\")) {\n                    stat.setTCPLoss(valEl, getInstantValue(\"TCPLoss\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPLostRetransmit\")) {\n                    stat.setTCPLostRetransmit(valEl, getInstantValue(\"TCPLostRetransmit\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPRenoFailures\")) {\n                    stat.setTCPRenoFailures(valEl, getInstantValue(\"TCPRenoFailures\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSackFailures\")) {\n                    stat.setTCPSackFailures(valEl, getInstantValue(\"TCPSackFailures\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPLossFailures\")) {\n                    stat.setTCPLossFailures(valEl, getInstantValue(\"TCPLossFailures\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPFastRetrans\")) {\n                    stat.setTCPFastRetrans(valEl, getInstantValue(\"TCPFastRetrans\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPForwardRetrans\")) {\n                    stat.setTCPForwardRetrans(valEl, getInstantValue(\"TCPForwardRetrans\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSlowStartRetrans\")) {\n                    stat.setTCPSlowStartRetrans(valEl, getInstantValue(\"TCPSlowStartRetrans\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPTimeouts\")) {\n                    stat.setTCPTimeouts(valEl, getInstantValue(\"TCPTimeouts\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPRenoRecoveryFail\")) {\n                    stat.setTCPRenoRecoveryFail(valEl, getInstantValue(\"TCPRenoRecoveryFail\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSackRecoveryFail\")) {\n                    stat.setTCPSackRecoveryFail(valEl, getInstantValue(\"TCPSackRecoveryFail\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPSchedulerFailed\")) {\n                    stat.setTCPSchedulerFailed(valEl, getInstantValue(\"TCPSchedulerFailed\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPRcvCollapsed\")) {\n                    stat.setTCPRcvCollapsed(valEl, getInstantValue(\"TCPRcvCollapsed\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDSACKOldSent\")) {\n                    stat.setTCPDSACKOldSent(valEl, getInstantValue(\"TCPDSACKOldSent\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDSACKOfoSent\")) {\n                    stat.setTCPDSACKOfoSent(valEl, getInstantValue(\"TCPDSACKOfoSent\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDSACKRecv\")) {\n                    stat.setTCPDSACKRecv(valEl, getInstantValue(\"TCPDSACKRecv\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPDSACKOfoRecv\")) {\n                    stat.setTCPDSACKOfoRecv(valEl, getInstantValue(\"TCPDSACKOfoRecv\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnSyn\")) {\n                    stat.setTCPAbortOnSyn(valEl, getInstantValue(\"TCPAbortOnSyn\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnData\")) {\n                    stat.setTCPAbortOnData(valEl, getInstantValue(\"TCPAbortOnData\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnClose\")) {\n                    stat.setTCPAbortOnClose(valEl, getInstantValue(\"TCPAbortOnClose\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnMemory\")) {\n                    stat.setTCPAbortOnMemory(valEl, getInstantValue(\"TCPAbortOnMemory\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnTimeout\")) {\n                    stat.setTCPAbortOnTimeout(valEl, getInstantValue(\"TCPAbortOnTimeout\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortOnLinger\")) {\n                    stat.setTCPAbortOnLinger(valEl, getInstantValue(\"TCPAbortOnLinger\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPAbortFailed\")) {\n                    stat.setTCPAbortFailed(valEl, getInstantValue(\"TCPAbortFailed\", stat.getTime(), valEl));\n                    continue;\n                }\n                if (el.equals(\"TCPMemoryPressures\")) {\n                    stat.setTCPMemoryPressures(valEl, getInstantValue(\"TCPMemoryPressures\", stat.getTime(), valEl));\n                    continue;\n                }\n            }\n        } catch (NoSuchElementException nse) { // done parsing\n        }\n        return stat;\n    }\n\n    public void getStatistics() {\n\n        ipStatistics = null;\n        tcpStatistics = null;\n        udpStatistics = null;\n        tcpExtStatistics = null;\n\n        // first parse /proc/net/snmp\n        try {\n            BufferedReader br = new BufferedReader(new FileReader(\"/proc/net/snmp\"));\n            while (true) {\n                // we need to read two lines at a time, the header and the actual values\n                final String header = br.readLine();\n                if (header == null) // end of stream\n                    break;\n                final String values = br.readLine();\n                if (values == null) // end of stream\n                    break;\n                if (header.startsWith(\"Ip: \") && values.startsWith(\"Ip: \")) {\n                    ipStatistics = parseIPTable(header.substring(4), values.substring(4), null);\n                    if (logger.isLoggable(Level.FINEST))\n                        logger.log(Level.FINE, ipStatistics.toString());\n                    continue;\n                }\n                if (header.startsWith(\"Tcp: \") && values.startsWith(\"Tcp: \")) {\n                    tcpStatistics = parseTCPTable(header.substring(5), values.substring(5), null);\n                    if (logger.isLoggable(Level.FINEST))\n                        logger.log(Level.FINE, tcpStatistics.toString());\n                    continue;\n                }\n                if (header.startsWith(\"Udp: \") && values.startsWith(\"Udp: \")) {\n                    udpStatistics = parseUDPTable(header.substring(5), values.substring(5), null);\n                    if (logger.isLoggable(Level.FINEST))\n                        logger.log(Level.FINE, udpStatistics.toString());\n                    continue;\n                }\n            }\n            br.close();\n        } catch (FileNotFoundException fne) {\n            if (out != null)\n                out.println(\"File /proc/net/snmp not found.\");\n            else\n                logger.info(\"File /proc/net/snmp not found.\");\n        } catch (IOException ioe) {\n            if (out != null) out.println(ioe.getLocalizedMessage());\n            else logger.warning(ioe.getLocalizedMessage());\n        }\n\n        // second parse /proc/net/netstat\n        try {\n            BufferedReader br = new BufferedReader(new FileReader(\"/proc/net/netstat\"));\n            while (true) {\n                // we need to read two lines at a time, the header and the actual values\n                final String header = br.readLine();\n                if (header == null) // end of stream\n                    break;\n                final String values = br.readLine();\n                if (values == null) // end of stream\n                    break;\n                if (header.startsWith(\"TcpExt: \") && values.startsWith(\"TcpExt: \")) {\n                    tcpExtStatistics = parseExtendedTCPTable(header.substring(8), values.substring(8), null);\n                    if (logger.isLoggable(Level.FINEST))\n                        logger.log(Level.FINE, tcpExtStatistics.toString());\n                    continue;\n                }\n            }\n            br.close();\n        } catch (FileNotFoundException fne) {\n            if (out != null)\n                out.println(\"File /proc/net/netstat not found.\");\n            else\n                logger.info(\"File /proc/net/netstat not found.\");\n        } catch (IOException ioe) {\n            if (out != null) out.println(ioe.getLocalizedMessage());\n            else logger.warning(ioe.getLocalizedMessage());\n        }\n    }\n\n    public final IPStatistics getIPStatistics() {\n        return ipStatistics;\n    }\n\n    public final TCPStatistics getTCPStatistics() {\n        return tcpStatistics;\n    }\n\n    public final UDPStatistics getUDPStatistics() {\n        return udpStatistics;\n    }\n\n    public final TCPExtStatistics getTCPExtStatistics() {\n        return tcpExtStatistics;\n    }\n\n    private final String prepareString(String str) {\n\n        // first try to make it double\n        try {\n            double d = Double.parseDouble(str);\n            if (!Double.isInfinite(d) && !Double.isNaN(d)) {\n                String n = nf.format(d);\n                n = n.replaceAll(\",\", \"\");\n                return n;\n            }\n        } catch (Throwable t) {\n        }\n\n        if (!str.contains(\".\")) {\n            return str + \".0000\";\n        }\n        int nr = str.lastIndexOf('.') + 1;\n        nr = str.length() - nr;\n        for (int i = nr; i < 4; i++)\n            str += \"0\";\n        return str;\n    }\n\n    public String addWithOverflowCheck(String newVal, String oldVal)\n            throws NumberFormatException {\n\n        if (newVal == null)\n            return oldVal;\n        if (oldVal == null)\n            return newVal;\n\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.add(oldv).toString();\n        }\n//\t\totherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return addWithOverflowCheck(newVal, oldVal);\n        }\n//\t\tso it's still 32 bits arch\n        return \"\" + (newv + oldv);\n    }\n\n    public String divideWithOverflowCheck(String newVal, String oldVal)\n            throws NumberFormatException {\n\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.divide(oldv, BigDecimal.ROUND_FLOOR).toString();\n        }\n//\t\totherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return divideWithOverflowCheck(newVal, oldVal);\n        }\n//\t\tso it's still 32 bits arch\n        return \"\" + (newv / oldv);\n    }\n\n    public String mulWithOverflowCheck(String newVal, String oldVal)\n            throws NumberFormatException {\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            return newv.multiply(oldv).toString();\n        }\n//\t\totherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return mulWithOverflowCheck(newVal, oldVal);\n        }\n//\t\tso it's still 32 bits arch\n        return \"\" + (newv * oldv);\n    }\n\n    public String diffWithOverflowCheck(String newVal, String oldVal)\n            throws NumberFormatException {\n        if (is64BitArch) {\n            String str = prepareString(newVal);\n            BigDecimal newv = null;\n            try {\n                newv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            str = prepareString(oldVal);\n            BigDecimal oldv = null;\n            try {\n                oldv = new BigDecimal(str);\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception \" + t + \" for \" + str);\n            }\n            if (newv.compareTo(oldv) >= 0)\n                return newv.subtract(oldv).toString();\n            BigInteger overflow = new BigInteger(\"1\").shiftLeft(64);\n            BigDecimal d = new BigDecimal(overflow.toString());\n            return newv.add(d).subtract(oldv).toString();\n        }\n//\t\totherwise we still assume 32 bits arch\n        double toCompare = 1L << 32;\n        double newv = Double.parseDouble(newVal);\n        double oldv = Double.parseDouble(oldVal);\n        if (newv >= toCompare || oldv >= toCompare) {\n            is64BitArch = true;\n            return diffWithOverflowCheck(newVal, oldVal);\n        }\n//\t\tso it's still 32 bits arch\n        if (newv >= oldv) {\n            return \"\" + (newv - oldv);\n        }\n        long vmax = 1L << 32; // 32 bits\n        return \"\" + (newv - oldv + vmax);\n    }\n\n    public void clear() {\n        ipStatistics = null;\n        tcpStatistics = null;\n        udpStatistics = null;\n        tcpExtStatistics = null;\n    }\n\n} // end of class StatisticsHandler\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/statistics/TCPExtStatistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.statistics;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\n/**\n * Extended statistics regarding the tcp protocol suite\n *\n * @author Ciprian Dobre\n */\npublic class TCPExtStatistics extends Statistics {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    /**\n     * SYN cookies sent\n     */\n    protected String syncookiesSent;\n    protected double syncookiesSentI;\n\n    /**\n     * SYN cookies received\n     */\n    protected String syncookiesRecv;\n    protected double syncookiesRecvI;\n\n    /**\n     * SYN cookies failed\n     */\n    protected String syncookiesFailed;\n    protected double syncookiesFailedI;\n\n    /**\n     * Packets pruned from receive queue because of buffer overrun\n     */\n    protected String pruneCalled;\n    protected double pruneCalledI;\n\n    /**\n     * resets received because of embryonic sockets\n     */\n    protected String embryonicRsts;\n    protected double embryonicRstsI;\n\n    /**\n     * Packets prunned from receive queue\n     */\n    protected String rcvPruned;\n    protected double rcvPrunedI;\n\n    /**\n     * Packets prunned from out-of-order queue because of overflow\n     */\n    protected String ofoPruned;\n    protected double ofoPrunedI;\n\n    /**\n     * tcp sockets finished time wait in fast timer\n     */\n    protected String tW;\n    protected double tWI;\n\n    /**\n     * sockets recicled by time stamp\n     */\n    protected String tWRecycled;\n    protected double tWRecycledI;\n\n    /**\n     * TCP sockets finished time wait in slow timer\n     */\n    protected String tWKilled;\n    protected double tWKilledI;\n\n    /**\n     * passive connections rejected because of timestamp\n     */\n    protected String pAWSPassive;\n    protected double pAWSPassiveI;\n\n    /**\n     * active connection rejected because of timestamp\n     */\n    protected String pAWSActive;\n    protected double pAWSActiveI;\n\n    /**\n     * packets rejected in established connection because of timestamp\n     */\n    protected String pAWSEstab;\n    protected double pAWSEstabI;\n\n    /**\n     * delayed acks sent\n     */\n    protected String delayedACKs;\n    protected double delayedACKsI;\n\n    /**\n     * delayed acks further delayed because of socket lock\n     */\n    protected String delayedACKLocked;\n    protected double delayedACKLockedI;\n\n    /**\n     * Quick ack mode activated times\n     */\n    protected String delayedACKLost;\n    protected double delayedACKLostI;\n\n    /**\n     * how many times the listening queue of a socket overflowed\n     */\n    protected String listenOverflows;\n    protected double listenOverflowsI;\n\n    /**\n     * SYNs to LISTEN sockets ignored\n     */\n    protected String listenDrops;\n    protected double listenDropsI;\n\n    /**\n     * packets directly queued to recvmsg - urgwent packets\n     */\n    protected String tCPPrequeued;\n    protected double tCPPrequeuedI;\n\n    /**\n     * packets directly received from backlog\n     */\n    protected String tCPDirectCopyFromBacklog;\n    protected double tCPDirectCopyFromBacklogI;\n\n    /**\n     * packets directly received from prequeue\n     */\n    protected String tCPDirectCopyFromPrequeue;\n    protected double tCPDirectCopyFromPrequeueI;\n\n    /**\n     * packets dropped from prequeue\n     */\n    protected String tCPPrequeueDropped;\n    protected double tCPPrequeueDroppedI;\n\n    /**\n     * packet headers predicted\n     */\n    protected String tCPHPHits;\n    protected double tCPHPHitsI;\n\n    /**\n     * packet headers predicted and directly queued to user\n     */\n    protected String tCPHPHitsToUser;\n    protected double tCPHPHitsToUserI;\n\n    /**\n     * how many times oom was encoutered when sending\n     */\n    protected String sockMallocOOM;\n    protected double sockMallocOOMI;\n\n    /**\n     * Pure ack recvd\n     */\n    protected String tCPPureAcks;\n    protected double tCPPureAcksI;\n\n    protected String tCPHPAcks;\n    protected double tCPHPAcksI;\n\n    protected String tCPRenoRecovery;\n    protected double tCPRenoRecoveryI;\n\n    protected String tCPSackRecovery;\n    protected double tCPSackRecoveryI;\n\n    protected String tCPSACKReneging;\n    protected double tCPSACKRenegingI;\n\n    protected String tCPFACKReorder;\n    protected double tCPFACKReorderI;\n\n    protected String tCPSACKReorder;\n    protected double tCPSACKReorderI;\n\n    protected String tCPRenoReorder;\n    protected double tCPRenoReorderI;\n\n    protected String tCPtSReorder;\n    protected double tCPtSReorderI;\n\n    protected String tCPFullUndo;\n    protected double tCPFullUndoI;\n\n    protected String tCPPartialUndo;\n    protected double tCPPartialUndoI;\n\n    protected String tCPDSACKUndo;\n    protected double tCPDSACKUndoI;\n\n    protected String tCPLossUndo;\n    protected double tCPLossUndoI;\n\n    protected String tCPLoss;\n    protected double tCPLossI;\n\n    protected String tCPLostRetransmit;\n    protected double tCPLostRetransmitI;\n\n    protected String tCPRenoFailures;\n    protected double tCPRenoFailuresI;\n\n    protected String tCPSackFailures;\n    protected double tCPSackFailuresI;\n\n    protected String tCPLossFailures;\n    protected double tCPLossFailuresI;\n\n    protected String tCPFastRetrans;\n    protected double tCPFastRetransI;\n\n    protected String tCPForwardRetrans;\n    protected double tCPForwardRetransI;\n\n    protected String tCPSlowStartRetrans;\n    protected double tCPSlowStartRetransI;\n\n    protected String tCPtimeouts;\n    protected double tCPtimeoutsI;\n\n    protected String tCPRenoRecoveryFail;\n    protected double tCPRenoRecoveryFailI;\n\n    protected String tCPSackRecoveryFail;\n    protected double tCPSackRecoveryFailI;\n\n    protected String tCPSchedulerFailed;\n    protected double tCPSchedulerFailedI;\n\n    protected String tCPRcvCollapsed;\n    protected double tCPRcvCollapsedI;\n\n    protected String tCPDSACKOldSent;\n    protected double tCPDSACKOldSentI;\n\n    protected String tCPDSACKOfoSent;\n    protected double tCPDSACKOfoSentI;\n\n    protected String tCPDSACKRecv;\n    protected double tCPDSACKRecvI;\n\n    protected String tCPDSACKOfoRecv;\n    protected double tCPDSACKOfoRecvI;\n\n    protected String tCPAbortOnSyn;\n    protected double tCPAbortOnSynI;\n\n    protected String tCPAbortOnData;\n    protected double tCPAbortOnDataI;\n\n    protected String tCPAbortOnClose;\n    protected double tCPAbortOnCloseI;\n\n    protected String tCPAbortOnMemory;\n    protected double tCPAbortOnMemoryI;\n\n    protected String tCPAbortOntimeout;\n    protected double tCPAbortOntimeoutI;\n\n    protected String tCPAbortOnLinger;\n    protected double tCPAbortOnLingerI;\n\n    protected String tCPAbortFailed;\n    protected double tCPAbortFailedI;\n\n    protected String tCPMemoryPressures;\n    protected double tCPMemoryPressuresI;\n\n    public TCPExtStatistics() {\n        super();\n    }\n\n    public final void setSyncookiesSent(final String syncookiesSent, final double syncookiesSentI) {\n        this.syncookiesSent = syncookiesSent;\n        this.syncookiesSentI = syncookiesSentI;\n    }\n\n    public final String getSyncookiesSent() {\n        return syncookiesSent;\n    }\n\n    public final double getSyncookiesSentI() {\n        return syncookiesSentI;\n    }\n\n    public final String getSyncookiesSentAsString() {\n        return syncookiesSent + \" SYN cookies sent\";\n    }\n\n    public final void setSyncookiesRecv(final String syncookiesRecv, final double syncookiesRecvI) {\n        this.syncookiesRecv = syncookiesRecv;\n        this.syncookiesRecvI = syncookiesRecvI;\n    }\n\n    public final String getSyncookiesRecv() {\n        return syncookiesRecv;\n    }\n\n    public final double getSyncookiesRecvI() {\n        return syncookiesRecvI;\n    }\n\n    public final String getSyncookiesRecvAsString() {\n        return syncookiesRecv + \" SYN cookies received\";\n    }\n\n    public final void setSyncookiesFailed(final String syncookiesFailed, final double syncookiesFailedI) {\n        this.syncookiesFailed = syncookiesFailed;\n        this.syncookiesFailedI = syncookiesFailedI;\n    }\n\n    public final String getSyncookiesFailed() {\n        return syncookiesFailed;\n    }\n\n    public final double getSyncookiesFailedI() {\n        return syncookiesFailedI;\n    }\n\n    public final String getSyncookiesFailedAsString() {\n        return syncookiesFailed + \" invalid SYN cookies received\";\n    }\n\n    public final void setEmbryonicRsts(final String embryonicRsts, final double embryonicRstsI) {\n        this.embryonicRsts = embryonicRsts;\n        this.embryonicRstsI = embryonicRstsI;\n    }\n\n    public final String getEmbryonicRsts() {\n        return embryonicRsts;\n    }\n\n    public final double getEmbryonicRstsI() {\n        return embryonicRstsI;\n    }\n\n    public final String getEmbryonicRstsAsString() {\n        return embryonicRsts + \" resets received for embryonic SYN_RECV sockets\";\n    }\n\n    public final void setPruneCalled(final String pruneCalled, final double pruneCalledI) {\n        this.pruneCalled = pruneCalled;\n        this.pruneCalledI = pruneCalledI;\n    }\n\n    public final String getPruneCalled() {\n        return pruneCalled;\n    }\n\n    public final double getPruneCalledI() {\n        return pruneCalledI;\n    }\n\n    public final String getPruneCalledAsString() {\n        return pruneCalled + \" packets pruned from receive queue because of socket buffer overrun\";\n    }\n\n    public final void setRcvPruned(final String rcvPruned, final double rcvPrunedI) {\n        this.rcvPruned = rcvPruned;\n        this.rcvPrunedI = rcvPrunedI;\n    }\n\n    public final String getRcvPruned() {\n        return rcvPruned;\n    }\n\n    public final double getRcvPrunedI() {\n        return rcvPrunedI;\n    }\n\n    public final String getRcvPrunedAsString() {\n        return rcvPruned + \" packets pruned from receive queue\";\n    }\n\n    public final void setOfoPruned(final String ofoPruned, final double ofoPrunedI) {\n        this.ofoPruned = ofoPruned;\n        this.ofoPrunedI = ofoPrunedI;\n    }\n\n    public final String getOfoPruned() {\n        return ofoPruned;\n    }\n\n    public final double getOfoPrunedI() {\n        return ofoPrunedI;\n    }\n\n    public final String getOfoPrunedAsString() {\n        return ofoPruned + \" packets dropped from out-of-order queue because of socket buffer overrun\";\n    }\n\n    public final void setTW(final String tW, final double tWI) {\n        this.tW = tW;\n        this.tWI = tWI;\n    }\n\n    public final String getTW() {\n        return tW;\n    }\n\n    public final double getTWI() {\n        return tWI;\n    }\n\n    public final String getTWAsString() {\n        return tW + \" TCP sockets finished time wait in fast timer\";\n    }\n\n    public final void setTWRecycled(final String tWRecycled, final double tWRecycledI) {\n        this.tWRecycled = tWRecycled;\n        this.tWRecycledI = tWRecycledI;\n    }\n\n    public final String getTWRecycled() {\n        return tWRecycled;\n    }\n\n    public final double getTWRecycledI() {\n        return tWRecycledI;\n    }\n\n    public final String getTWRecycledAsString() {\n        return tWRecycled + \" time wait sockets recycled by time stamp\";\n    }\n\n    public final void setTWKilled(final String tWKilled, final double tWKilledI) {\n        this.tWKilled = tWKilled;\n        this.tWKilledI = tWKilledI;\n    }\n\n    public final String getTWKilled() {\n        return tWKilled;\n    }\n\n    public final double getTWKilledI() {\n        return tWKilledI;\n    }\n\n    public final String getTWKilledAsString() {\n        return tWKilled + \" TCP sockets finished time wait in slow timer\";\n    }\n\n    public final void setPAWSPassive(final String pAWSPassive, final double pAWSPassiveI) {\n        this.pAWSPassive = pAWSPassive;\n        this.pAWSPassiveI = pAWSPassiveI;\n    }\n\n    public final String getPAWSPassive() {\n        return pAWSPassive;\n    }\n\n    public final double getPAWSPassiveI() {\n        return pAWSPassiveI;\n    }\n\n    public final String getPAWSPassiveAsString() {\n        return pAWSPassive + \" passive connections rejected because of time stamp\";\n    }\n\n    public final void setPAWSActive(final String pAWSActive, final double pAWSActiveI) {\n        this.pAWSActive = pAWSActive;\n        this.pAWSActiveI = pAWSActiveI;\n    }\n\n    public final String getPAWSActive() {\n        return pAWSActive;\n    }\n\n    public final double getPAWSActiveI() {\n        return pAWSActiveI;\n    }\n\n    public final String getPAWSActiveAsString() {\n        return pAWSActive + \" active connections rejected because of time stamp\";\n    }\n\n    public final void setPAWSEstab(final String pAWSEstab, final double pAWSEstabI) {\n        this.pAWSEstab = pAWSEstab;\n        this.pAWSEstabI = pAWSEstabI;\n    }\n\n    public final String getPAWSEstab() {\n        return pAWSEstab;\n    }\n\n    public final double getPAWSEstabI() {\n        return pAWSEstabI;\n    }\n\n    public final String getPAWSEstabAsString() {\n        return pAWSEstab + \" packets rejects in established connections because of timestamp\";\n    }\n\n    public final void setDelayedACKs(final String delayedACKs, final double delayedACKsI) {\n        this.delayedACKs = delayedACKs;\n        this.delayedACKsI = delayedACKsI;\n    }\n\n    public final String getDelayedACKs() {\n        return delayedACKs;\n    }\n\n    public final double getDelayedACKsI() {\n        return delayedACKsI;\n    }\n\n    public final String getDelayedACKsAsString() {\n        return delayedACKs + \" delayed acks sent\";\n    }\n\n    public final void setDelayedACKLocked(final String delayedACKLocked, final double delayedACKLockedI) {\n        this.delayedACKLocked = delayedACKLocked;\n        this.delayedACKLockedI = delayedACKLockedI;\n    }\n\n    public final String getDelayedACKLocked() {\n        return delayedACKLocked;\n    }\n\n    public final double getDelayedACKLockedI() {\n        return delayedACKLockedI;\n    }\n\n    public final String getDelayedACKLockedAsString() {\n        return delayedACKLocked + \" delayed acks further delayed because of locked socket\";\n    }\n\n    public final void setDelayedACKLost(final String delayedACKLost, final double delayedACKLostI) {\n        this.delayedACKLost = delayedACKLost;\n        this.delayedACKLostI = delayedACKLostI;\n    }\n\n    public final String getDelayedACKLost() {\n        return delayedACKLost;\n    }\n\n    public final double getDelayedACKLostI() {\n        return delayedACKLostI;\n    }\n\n    public final String getDelayedACKLostAsString() {\n        return \"Quick ack mode was activated \" + delayedACKLost + \" times\";\n    }\n\n    public final void setListenOverflows(final String listenOverflows, final double listenOverflowsI) {\n        this.listenOverflows = listenOverflows;\n        this.listenOverflowsI = listenOverflowsI;\n    }\n\n    public final String getListenOverflows() {\n        return listenOverflows;\n    }\n\n    public final double getListenOverflowsI() {\n        return listenOverflowsI;\n    }\n\n    public final String getListenOverflowsAsString() {\n        return listenOverflows + \" times the listen queue of a socket overflowed\";\n    }\n\n    public final void setListenDrops(final String listenDrops, final double listenDropsI) {\n        this.listenDrops = listenDrops;\n        this.listenDropsI = listenDropsI;\n    }\n\n    public final String getListenDrops() {\n        return listenDrops;\n    }\n\n    public final double getListenDropsI() {\n        return listenDropsI;\n    }\n\n    public final String getListenDropsAsString() {\n        return listenDrops + \" SYNs to LISTEN sockets ignored\";\n    }\n\n    public final void setTCPPrequeued(final String tCPPrequeued, final double tCPPrequeuedI) {\n        this.tCPPrequeued = tCPPrequeued;\n        this.tCPPrequeuedI = tCPPrequeuedI;\n    }\n\n    public final String getTCPPrequeued() {\n        return tCPPrequeued;\n    }\n\n    public final double getTCPPrequeuedI() {\n        return tCPPrequeuedI;\n    }\n\n    public final String getTCPPrequeuedAsString() {\n        return tCPPrequeued + \" packets directly queued to recvmsg prequeue\";\n    }\n\n    public final void setTCPDirectCopyFromBacklog(final String tCPDirectCopyFromBacklog, final double tCPDirectCopyFromBacklogI) {\n        this.tCPDirectCopyFromBacklog = tCPDirectCopyFromBacklog;\n        this.tCPDirectCopyFromBacklogI = tCPDirectCopyFromBacklogI;\n    }\n\n    public final String getTCPDirectCopyFromBacklog() {\n        return tCPDirectCopyFromBacklog;\n    }\n\n    public final double getTCPDirectCopyFromBacklogI() {\n        return tCPDirectCopyFromBacklogI;\n    }\n\n    public final String getTCPDirectCopyFromBacklogAsString() {\n        return tCPDirectCopyFromBacklog + \" packets directly received from backlog\";\n    }\n\n    public final void setTCPDirectCopyFromPrequeue(final String tCPDirectCopyFromPrequeue, final double tCPDirectCopyFromPrequeueI) {\n        this.tCPDirectCopyFromPrequeue = tCPDirectCopyFromPrequeue;\n        this.tCPDirectCopyFromPrequeueI = tCPDirectCopyFromPrequeueI;\n    }\n\n    public final String getTCPDirectCopyFromPrequeue() {\n        return tCPDirectCopyFromPrequeue;\n    }\n\n    public final double getTCPDirectCopyFromPrequeueI() {\n        return tCPDirectCopyFromPrequeueI;\n    }\n\n    public final String getTCPDirectCopyFromPrequeueAsString() {\n        return tCPDirectCopyFromPrequeue + \" packets directly received from prequeue\";\n    }\n\n    public final void setTCPPrequeueDropped(final String tCPPrequeueDropped, final double tCPPrequeueDroppedI) {\n        this.tCPPrequeueDropped = tCPPrequeueDropped;\n        this.tCPPrequeueDroppedI = tCPPrequeueDroppedI;\n    }\n\n    public final String getTCPPrequeueDropped() {\n        return tCPPrequeueDropped;\n    }\n\n    public final double getTCPPrequeueDroppedI() {\n        return tCPPrequeueDroppedI;\n    }\n\n    public final String getTCPPrequeueDroppedAsString() {\n        return tCPPrequeueDropped + \" packets dropped from prequeue\";\n    }\n\n    public final void setTCPHPHits(final String tCPHPHits, final double tCPHPHitsI) {\n        this.tCPHPHits = tCPHPHits;\n        this.tCPHPHitsI = tCPHPHitsI;\n    }\n\n    public final String getTCPHPHits() {\n        return tCPHPHits;\n    }\n\n    public final double getTCPHPHitsI() {\n        return tCPHPHitsI;\n    }\n\n    public final String getTCPHPHitsAsString() {\n        return tCPHPHits + \" packets header predicted\";\n    }\n\n    public final void setTCPHPHitsToUser(final String tCPHPHitsToUser, final double tCPHPHitsToUserI) {\n        this.tCPHPHitsToUser = tCPHPHitsToUser;\n        this.tCPHPHitsToUserI = tCPHPHitsToUserI;\n    }\n\n    public final String getTCPHPHitsToUser() {\n        return tCPHPHitsToUser;\n    }\n\n    public final double getTCPHPHitsToUserI() {\n        return tCPHPHitsToUserI;\n    }\n\n    public final String getTCPHPHitsToUserAsString() {\n        return tCPHPHitsToUser + \" packets header predicted and directly queued to user\";\n    }\n\n    public final void setSockMallocOOM(final String sockMallocOOM, final double sockMallocOOMI) {\n        this.sockMallocOOM = sockMallocOOM;\n        this.sockMallocOOMI = sockMallocOOMI;\n    }\n\n    public final String getSockMallocOOM() {\n        return sockMallocOOM;\n    }\n\n    public final double getSockMallocOOMI() {\n        return sockMallocOOMI;\n    }\n\n    public final String getSockMallocOOMAsString() {\n        return \"Ran \" + sockMallocOOM + \" times out of system memory during packet sending\";\n    }\n\n    public final void setTCPPureAcks(final String tCPPureAcks, final double tCPPureAcksI) {\n        this.tCPPureAcks = tCPPureAcks;\n        this.tCPPureAcksI = tCPPureAcksI;\n    }\n\n    public final String getTCPPureAcks() {\n        return tCPPureAcks;\n    }\n\n    public final double getTCPPureAcksI() {\n        return tCPPureAcksI;\n    }\n\n    public final void setTCPHPAcks(final String tCPHPAcks, final double tCPHPAcksI) {\n        this.tCPHPAcks = tCPHPAcks;\n        this.tCPHPAcksI = tCPHPAcksI;\n    }\n\n    public final String getTCPHPAcks() {\n        return tCPHPAcks;\n    }\n\n    public final double getTCPHPAcksI() {\n        return tCPHPAcksI;\n    }\n\n    public final void setTCPRenoRecovery(final String tCPRenoRecovery, final double tCPRenoRecoveryI) {\n        this.tCPRenoRecovery = tCPRenoRecovery;\n        this.tCPRenoRecoveryI = tCPRenoRecoveryI;\n    }\n\n    public final String getTCPRenoRecovery() {\n        return tCPRenoRecovery;\n    }\n\n    public final double getTCPRenoRecoveryI() {\n        return tCPRenoRecoveryI;\n    }\n\n    public final void setTCPSackRecovery(final String tCPSackRecovery, final double tCPSackRecoveryI) {\n        this.tCPSackRecovery = tCPSackRecovery;\n        this.tCPSackRecoveryI = tCPSackRecoveryI;\n    }\n\n    public final String getTCPSackRecovery() {\n        return tCPSackRecovery;\n    }\n\n    public final double getTCPSackRecoveryI() {\n        return tCPSackRecoveryI;\n    }\n\n    public String toString() {\n        final StringBuffer buf = new StringBuffer();\n        buf.append(\"Extended TCP Statistics:\\n\");\n        buf.append(getSyncookiesSentAsString()).append(\"\\n\");\n        buf.append(getSyncookiesRecvAsString()).append(\"\\n\");\n        buf.append(getSyncookiesFailedAsString()).append(\"\\n\");\n        buf.append(getEmbryonicRstsAsString()).append(\"\\n\");\n        buf.append(getPruneCalledAsString()).append(\"\\n\");\n        buf.append(getRcvPrunedAsString()).append(\"\\n\");\n        buf.append(getOfoPrunedAsString()).append(\"\\n\");\n        buf.append(getTWAsString()).append(\"\\n\");\n        buf.append(getTWRecycledAsString()).append(\"\\n\");\n        buf.append(getTWKilledAsString()).append(\"\\n\");\n        buf.append(getPAWSPassiveAsString()).append(\"\\n\");\n        buf.append(getPAWSActiveAsString()).append(\"\\n\");\n        buf.append(getPAWSEstabAsString()).append(\"\\n\");\n        buf.append(getDelayedACKsAsString()).append(\"\\n\");\n        buf.append(getDelayedACKLockedAsString()).append(\"\\n\");\n        buf.append(getDelayedACKLostAsString()).append(\"\\n\");\n        buf.append(getListenOverflowsAsString()).append(\"\\n\");\n        buf.append(getListenDropsAsString()).append(\"\\n\");\n        buf.append(getTCPPrequeuedAsString()).append(\"\\n\");\n        buf.append(getTCPDirectCopyFromBacklogAsString()).append(\"\\n\");\n        buf.append(getTCPDirectCopyFromPrequeueAsString()).append(\"\\n\");\n        buf.append(getTCPPrequeueDroppedAsString()).append(\"\\n\");\n        buf.append(getTCPHPHitsAsString()).append(\"\\n\");\n        buf.append(getTCPHPHitsToUserAsString()).append(\"\\n\");\n        buf.append(getSockMallocOOMAsString()).append(\"\\n\");\n        return buf.toString();\n    }\n\n    public void setTCPDSACKUndo(String undo, double undoI) {\n        tCPDSACKUndo = undo;\n        tCPDSACKUndoI = undoI;\n    }\n\n    public String getTCPDSACKUndo() {\n        return tCPDSACKUndo;\n    }\n\n    public double getTCPDSACKUndoI() {\n        return tCPDSACKUndoI;\n    }\n\n    public void setTCPFACKReorder(String reorder, double reorderI) {\n        tCPFACKReorder = reorder;\n        tCPFACKReorderI = reorderI;\n    }\n\n    public String getTCPFACKReorder() {\n        return tCPFACKReorder;\n    }\n\n    public double getTCPFACKReorderI() {\n        return tCPFACKReorderI;\n    }\n\n    public void setTCPFullUndo(String fullUndo, double fullUndoI) {\n        tCPFullUndo = fullUndo;\n        tCPFullUndoI = fullUndoI;\n    }\n\n    public String getTCPFullUndo() {\n        return tCPFullUndo;\n    }\n\n    public double getTCPFullUndoI() {\n        return tCPFullUndoI;\n    }\n\n    public void setTCPLoss(String loss, double lossI) {\n        tCPLoss = loss;\n        tCPLossI = lossI;\n    }\n\n    public String getTCPLoss() {\n        return tCPLoss;\n    }\n\n    public double getTCPLossI() {\n        return tCPLossI;\n    }\n\n    public void setTCPLossFailures(String lossFailures, double lossFailuresI) {\n        tCPLossFailures = lossFailures;\n        tCPLossFailuresI = lossFailuresI;\n    }\n\n    public String getTCPLossFailures() {\n        return tCPLossFailures;\n    }\n\n    public double getTCPLossFailuresI() {\n        return tCPLossFailuresI;\n    }\n\n    public void setTCPLossUndo(String lossUndo, double lossUndoI) {\n        tCPLossUndo = lossUndo;\n        tCPLossUndoI = lossUndoI;\n    }\n\n    public String getTCPLossUndo() {\n        return tCPLossUndo;\n    }\n\n    public double getTCPLossUndoI() {\n        return tCPLossUndoI;\n    }\n\n    public void setTCPLostRetransmit(String lostRetransmit, double lostRetransmitI) {\n        tCPLostRetransmit = lostRetransmit;\n        tCPLostRetransmitI = lostRetransmitI;\n    }\n\n    public String getTCPLostRetransmit() {\n        return tCPLostRetransmit;\n    }\n\n    public double getTCPLostRetransmitI() {\n        return tCPLostRetransmitI;\n    }\n\n    public void setTCPPartialUndo(String partialUndo, double partialUndoI) {\n        tCPPartialUndo = partialUndo;\n        tCPPartialUndoI = partialUndoI;\n    }\n\n    public String getTCPPartialUndo() {\n        return tCPPartialUndo;\n    }\n\n    public double getTCPPartialUndoI() {\n        return tCPPartialUndoI;\n    }\n\n    public void setTCPRenoFailures(String renoFailures, double renoFailuresI) {\n        tCPRenoFailures = renoFailures;\n        tCPRenoFailuresI = renoFailuresI;\n    }\n\n    public String getTCPRenoFailures() {\n        return tCPRenoFailures;\n    }\n\n    public double getTCPRenoFailuresI() {\n        return tCPRenoFailuresI;\n    }\n\n    public void setTCPRenoReorder(String renoReorder, double renoReorderI) {\n        tCPRenoReorder = renoReorder;\n        tCPRenoReorderI = renoReorderI;\n    }\n\n    public String getTCPRenoReorder() {\n        return tCPRenoReorder;\n    }\n\n    public double getTCPRenoReorderI() {\n        return tCPRenoReorderI;\n    }\n\n    public void setTCPSackFailures(String sackFailures, double sackFailuresI) {\n        tCPSackFailures = sackFailures;\n        tCPSackFailuresI = sackFailuresI;\n    }\n\n    public String getTCPSackFailures() {\n        return tCPSackFailures;\n    }\n\n    public double getTCPSackFailuresI() {\n        return tCPSackFailuresI;\n    }\n\n    public void setTCPSACKReneging(String reneging, double renegingI) {\n        tCPSACKReneging = reneging;\n        tCPSACKRenegingI = renegingI;\n    }\n\n    public String getTCPSACKReneging() {\n        return tCPSACKReneging;\n    }\n\n    public double getTCPSACKRenegingI() {\n        return tCPSACKRenegingI;\n    }\n\n    public void setTCPSACKReorder(String reorder, double reorderI) {\n        tCPSACKReorder = reorder;\n        tCPSACKReorderI = reorderI;\n    }\n\n    public String getTCPSACKReorder() {\n        return tCPSACKReorder;\n    }\n\n    public double getTCPSACKReorderI() {\n        return tCPSACKReorderI;\n    }\n\n    public void setTCPTSReorder(String ptSReorder, double ptSReorderI) {\n        tCPtSReorder = ptSReorder;\n        tCPtSReorderI = ptSReorderI;\n    }\n\n    public String getTCPTSReorder() {\n        return tCPtSReorder;\n    }\n\n    public double getTCPTSReorderI() {\n        return tCPtSReorderI;\n    }\n\n    public void setTCPAbortFailed(String abortFailed, double abortFailedI) {\n        tCPAbortFailed = abortFailed;\n        tCPAbortFailedI = abortFailedI;\n    }\n\n    public String getTCPAbortFailed() {\n        return tCPAbortFailed;\n    }\n\n    public double getTCPAbortFailedI() {\n        return tCPAbortFailedI;\n    }\n\n    public void setTCPAbortOnClose(String abortOnClose, double abortOnCloseI) {\n        tCPAbortOnClose = abortOnClose;\n        tCPAbortOnCloseI = abortOnCloseI;\n    }\n\n    public String getTCPAbortOnClose() {\n        return tCPAbortOnClose;\n    }\n\n    public double getTCPAbortOnCloseI() {\n        return tCPAbortOnCloseI;\n    }\n\n    public void setTCPAbortOnData(String abortOnData, double abortOnDataI) {\n        tCPAbortOnData = abortOnData;\n        tCPAbortOnDataI = abortOnDataI;\n    }\n\n    public String getTCPAbortOnData() {\n        return tCPAbortOnData;\n    }\n\n    public double getTCPAbortOnDataI() {\n        return tCPAbortOnDataI;\n    }\n\n    public void setTCPAbortOnLinger(String abortOnLinger, double abortOnLingerI) {\n        tCPAbortOnLinger = abortOnLinger;\n        tCPAbortOnLingerI = abortOnLingerI;\n    }\n\n    public String getTCPAbortOnLinger() {\n        return tCPAbortOnLinger;\n    }\n\n    public double getTCPAbortOnLingerI() {\n        return tCPAbortOnLingerI;\n    }\n\n    public void setTCPAbortOnMemory(String abortOnMemory, double abortOnMemoryI) {\n        tCPAbortOnMemory = abortOnMemory;\n        tCPAbortOnMemoryI = abortOnMemoryI;\n    }\n\n    public String getTCPAbortOnMemory() {\n        return tCPAbortOnMemory;\n    }\n\n    public double getTCPAbortOnMemoryI() {\n        return tCPAbortOnMemoryI;\n    }\n\n    public void setTCPAbortOnSyn(String abortOnSyn, double abortOnSynI) {\n        tCPAbortOnSyn = abortOnSyn;\n        tCPAbortOnSynI = abortOnSynI;\n    }\n\n    public String getTCPAbortOnSyn() {\n        return tCPAbortOnSyn;\n    }\n\n    public double getTCPAbortOnSynI() {\n        return tCPAbortOnSynI;\n    }\n\n    public void setTCPAbortOnTimeout(String abortOntimeout, double abortOntimeoutI) {\n        tCPAbortOntimeout = abortOntimeout;\n        tCPAbortOntimeoutI = abortOntimeoutI;\n    }\n\n    public String getTCPAbortOnTimeout() {\n        return tCPAbortOntimeout;\n    }\n\n    public double getTCPAbortOnTimeoutI() {\n        return tCPAbortOntimeoutI;\n    }\n\n    public void setTCPDSACKOfoRecv(String ofoRecv, double ofoRecvI) {\n        tCPDSACKOfoRecv = ofoRecv;\n        tCPDSACKOfoRecvI = ofoRecvI;\n    }\n\n    public String getTCPDSACKOfoRecv() {\n        return tCPDSACKOfoRecv;\n    }\n\n    public double getTCPDSACKOfoRecvI() {\n        return tCPDSACKOfoRecvI;\n    }\n\n    public void setTCPDSACKOfoSent(String ofoSent, double ofoSentI) {\n        tCPDSACKOfoSent = ofoSent;\n        tCPDSACKOfoSentI = ofoSentI;\n    }\n\n    public String getTCPDSACKOfoSent() {\n        return tCPDSACKOfoSent;\n    }\n\n    public double getTCPDSACKOfoSentI() {\n        return tCPDSACKOfoSentI;\n    }\n\n    public void setTCPDSACKOldSent(String oldSent, double oldSentI) {\n        tCPDSACKOldSent = oldSent;\n        tCPDSACKOldSentI = oldSentI;\n    }\n\n    public String getTCPDSACKOldSent() {\n        return tCPDSACKOldSent;\n    }\n\n    public double getTCPDSACKOldSentI() {\n        return tCPDSACKOldSentI;\n    }\n\n    public void setTCPDSACKRecv(String recv, double recvI) {\n        tCPDSACKRecv = recv;\n        tCPDSACKRecvI = recvI;\n    }\n\n    public String getTCPDSACKRecv() {\n        return tCPDSACKRecv;\n    }\n\n    public double getTCPDSACKRecvI() {\n        return tCPDSACKRecvI;\n    }\n\n    public void setTCPFastRetrans(String fastRetrans, double fastRetransI) {\n        tCPFastRetrans = fastRetrans;\n        tCPFastRetransI = fastRetransI;\n    }\n\n    public String getTCPFastRetrans() {\n        return tCPFastRetrans;\n    }\n\n    public double getTCPFastRetransI() {\n        return tCPFastRetransI;\n    }\n\n    public void setTCPForwardRetrans(String forwardRetrans, double forwardRetransI) {\n        tCPForwardRetrans = forwardRetrans;\n        tCPForwardRetransI = forwardRetransI;\n    }\n\n    public String getTCPForwardRetrans() {\n        return tCPForwardRetrans;\n    }\n\n    public double getTCPForwardRetransI() {\n        return tCPForwardRetransI;\n    }\n\n    public void setTCPMemoryPressures(String memoryPressures, double memoryPressuresI) {\n        tCPMemoryPressures = memoryPressures;\n        tCPMemoryPressuresI = memoryPressuresI;\n    }\n\n    public String getTCPMemoryPressures() {\n        return tCPMemoryPressures;\n    }\n\n    public double getTCPMemoryPressuresI() {\n        return tCPMemoryPressuresI;\n    }\n\n    public void setTCPRcvCollapsed(String rcvCollapsed, double rcvCollapsedI) {\n        tCPRcvCollapsed = rcvCollapsed;\n        tCPRcvCollapsedI = rcvCollapsedI;\n    }\n\n    public String getTCPRcvCollapsed() {\n        return tCPRcvCollapsed;\n    }\n\n    public double getTCPRcvCollapsedI() {\n        return tCPRcvCollapsedI;\n    }\n\n    public void setTCPRenoRecoveryFail(String renoRecoveryFail, double renoRecoveryFailI) {\n        tCPRenoRecoveryFail = renoRecoveryFail;\n        tCPRenoRecoveryFailI = renoRecoveryFailI;\n    }\n\n    public String getTCPRenoRecoveryFail() {\n        return tCPRenoRecoveryFail;\n    }\n\n    public double getTCPRenoRecoveryFailI() {\n        return tCPRenoRecoveryFailI;\n    }\n\n    public void setTCPSackRecoveryFail(String sackRecoveryFail, double sackRecoveryFailI) {\n        tCPSackRecoveryFail = sackRecoveryFail;\n        tCPSackRecoveryFailI = sackRecoveryFailI;\n    }\n\n    public String getTCPSackRecoveryFail() {\n        return tCPSackRecoveryFail;\n    }\n\n    public double getTCPSackRecoveryFailI() {\n        return tCPSackRecoveryFailI;\n    }\n\n    public void setTCPSchedulerFailed(String schedulerFailed, double schedulerFailedI) {\n        tCPSchedulerFailed = schedulerFailed;\n        tCPSchedulerFailedI = schedulerFailedI;\n    }\n\n    public String getTCPSchedulerFailed() {\n        return tCPSchedulerFailed;\n    }\n\n    public double getTCPSchedulerFailedI() {\n        return tCPSchedulerFailedI;\n    }\n\n    public void setTCPSlowStartRetrans(String slowStartRetrans, double slowStartRetransI) {\n        tCPSlowStartRetrans = slowStartRetrans;\n        tCPSlowStartRetransI = slowStartRetransI;\n    }\n\n    public String getTCPSlowStartRetrans() {\n        return tCPSlowStartRetrans;\n    }\n\n    public double getTCPSlowStartRetransI() {\n        return tCPSlowStartRetransI;\n    }\n\n    public void setTCPTimeouts(String ptimeouts, double ptimeoutsI) {\n        tCPtimeouts = ptimeouts;\n        tCPtimeoutsI = ptimeoutsI;\n    }\n\n    public String getTCPTimeouts() {\n        return tCPtimeouts;\n    }\n\n    public double getTCPTimeoutsI() {\n        return tCPtimeoutsI;\n    }\n\n} // end of class TCPExtStatistics\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/statistics/TCPStatistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.statistics;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\n/**\n * Statistics regarding the tcp protocol suite\n *\n * @author Ciprian Dobre\n */\npublic class TCPStatistics extends Statistics {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    /**\n     * The minimum restransmission timeout value\n     */\n    protected long rToMin = 0;\n\n    /**\n     * The maximum retransmission timeout value\n     */\n    protected long rToMax = 0;\n\n    /**\n     * Active connection openned\n     */\n    protected String activeOpens = \"0\";\n    protected double activeOpensI = 0D;\n\n    /**\n     * Passive connection openned\n     */\n    protected String passiveOpens = \"0\";\n    protected double passiveOpensI = 0D;\n\n    /**\n     * Failed connection attempts\n     */\n    protected String attemptFails = \"0\";\n    protected double attemptFailsI = 0D;\n\n    /**\n     * Connection resets received\n     */\n    protected String estabResets = \"0\";\n    protected double estabResetsI = 0D;\n\n    /**\n     * Connections established\n     */\n    protected long currEstab = 0;\n\n    /**\n     * Segments received\n     */\n    protected String inSegs = \"0\";\n    protected double inSegsI = 0;\n\n    /**\n     * Segments sent\n     */\n    protected String outSegs = \"0\";\n    protected double outSegsI = 0D;\n\n    /**\n     * Segments retransmitted\n     */\n    protected String retransSegs = \"0\";\n    protected double retransSegsI = 0D;\n\n    /**\n     * Bad segments received\n     */\n    protected String inErrs = \"0\";\n    protected double inErrsI = 0D;\n\n    /**\n     * Resets sent\n     */\n    protected String outRsts = \"0\";\n    protected double outRstsI = 0D;\n\n    public TCPStatistics() {\n        super();\n    }\n\n    public final long getRToMin() {\n        return rToMin;\n    }\n\n    public final void setRToMin(final long rToMin) {\n        this.rToMin = rToMin;\n    }\n\n    public final String getRToMinAsString() {\n        return \"The minimum retransmission timeout value is \" + rToMin;\n    }\n\n    public final long getRToMax() {\n        return rToMax;\n    }\n\n    public final void setRToMax(final long rToMax) {\n        this.rToMax = rToMax;\n    }\n\n    public final String getRToMaxAsString() {\n        return \"The maximum retransmission timeout value is \" + rToMax;\n    }\n\n    public final void setActiveOpens(final String activeOpens, final double activeOpensI) {\n        this.activeOpens = activeOpens;\n        this.activeOpensI = activeOpensI;\n    }\n\n    public final String getActiveOpens() {\n        return activeOpens;\n    }\n\n    public final double getActiveOpensI() {\n        return activeOpensI;\n    }\n\n    public final String getActiveOpensAsString() {\n        return activeOpens + \" active connections openings\";\n    }\n\n    public final void setPassiveOpens(final String passiveOpens, final double passiveOpensI) {\n        this.passiveOpens = passiveOpens;\n        this.passiveOpensI = passiveOpensI;\n    }\n\n    public final String getPassiveOpens() {\n        return passiveOpens;\n    }\n\n    public final double getPassiveOpensI() {\n        return passiveOpensI;\n    }\n\n    public final String getPassiveOpensAsString() {\n        return passiveOpens + \" passive connection openings\";\n    }\n\n    public final void setAttemptFails(final String attemptFails, final double attemptFailsI) {\n        this.attemptFails = attemptFails;\n        this.attemptFailsI = attemptFailsI;\n    }\n\n    public final String getAttemptFails() {\n        return attemptFails;\n    }\n\n    public final double getAttemptFailsI() {\n        return attemptFailsI;\n    }\n\n    public final String getAttemptFailsAsString() {\n        return attemptFails + \" failed connection attempts\";\n    }\n\n    public final void setEstabResets(final String estabResets, final double estabResetsI) {\n        this.estabResets = estabResets;\n        this.estabResetsI = estabResetsI;\n    }\n\n    public final String getEstabResets() {\n        return estabResets;\n    }\n\n    public final double getEstabResetsI() {\n        return estabResetsI;\n    }\n\n    public final String getEstabResetsAsString() {\n        return estabResets + \" connection resets received\";\n    }\n\n    public final long getCurrEstab() {\n        return currEstab;\n    }\n\n    public final void setCurrEstab(final long currEstab) {\n        this.currEstab = currEstab;\n    }\n\n    public final String getCurrEstabAsString() {\n        return currEstab + \" connections established\";\n    }\n\n    public final void setInSegs(final String inSegs, final double inSegsI) {\n        this.inSegs = inSegs;\n        this.inSegsI = inSegsI;\n    }\n\n    public final String getInSegs() {\n        return inSegs;\n    }\n\n    public final double getInSegsI() {\n        return inSegsI;\n    }\n\n    public final String getInSegsAsString() {\n        return inSegs + \" segments received\";\n    }\n\n    public final void setOutSegs(final String outSegs, final double outSegsI) {\n        this.outSegs = outSegs;\n        this.outSegsI = outSegsI;\n    }\n\n    public final String getOutSegs() {\n        return outSegs;\n    }\n\n    public final double getOutSegsI() {\n        return outSegsI;\n    }\n\n    public final String getOutSegsAsString() {\n        return outSegs + \" segments send out\";\n    }\n\n    public final void setRetransSegs(final String retransSegs, final double retransSegsI) {\n        this.retransSegs = retransSegs;\n        this.retransSegsI = retransSegsI;\n    }\n\n    public final String getRetransSegs() {\n        return retransSegs;\n    }\n\n    public final double getRetransSegsI() {\n        return retransSegsI;\n    }\n\n    public final String getRetransSegsAsString() {\n        return retransSegs + \" segments retransmited\";\n    }\n\n    public final void setInErrs(final String inErrs, final double inErrsI) {\n        this.inErrs = inErrs;\n        this.inErrsI = inErrsI;\n    }\n\n    public final String getInErrs() {\n        return inErrs;\n    }\n\n    public final double getInErrsI() {\n        return inErrsI;\n    }\n\n    public final String getInErrsAsString() {\n        return inErrs + \" bad segments received\";\n    }\n\n    public final void setOutRsts(final String outRsts, final double outRstsI) {\n        this.outRsts = outRsts;\n        this.outRstsI = outRstsI;\n    }\n\n    public final String getOutRsts() {\n        return outRsts;\n    }\n\n    public final double getOutRstsI() {\n        return outRstsI;\n    }\n\n    public final String getOutRstsAsString() {\n        return outRsts + \" resets sent\";\n    }\n\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n        buf.append(\"TCP Statistics:\\n\");\n        buf.append(getRToMinAsString()).append(\"\\n\");\n        buf.append(getRToMaxAsString()).append(\"\\n\");\n        buf.append(getActiveOpensAsString()).append(\"\\n\");\n        buf.append(getPassiveOpensAsString()).append(\"\\n\");\n        buf.append(getAttemptFailsAsString()).append(\"\\n\");\n        buf.append(getEstabResetsAsString()).append(\"\\n\");\n        buf.append(getCurrEstabAsString()).append(\"\\n\");\n        buf.append(getInSegsAsString()).append(\"\\n\");\n        buf.append(getOutSegsAsString()).append(\"\\n\");\n        buf.append(getRetransSegsAsString()).append(\"\\n\");\n        buf.append(getInErrsAsString()).append(\"\\n\");\n        buf.append(getOutRstsAsString()).append(\"\\n\");\n        return buf.toString();\n    }\n\n} // end of class TCPStatistics\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/net/statistics/UDPStatistics.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.net.statistics;\n\nimport lia.util.net.copy.monitoring.lisa.net.Statistics;\n\n/**\n * Statistics regarding the udp protocol suite\n *\n * @author Ciprian Dobre\n */\npublic class UDPStatistics extends Statistics {\n\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n\n    /**\n     * Datagrams received\n     */\n    protected String inDatagrams = \"0\";\n    protected double inDatagramsI = 0D;\n\n    /**\n     * Datagrams to unknown ports received\n     */\n    protected String noPorts = \"0\";\n    protected double noPortsI = 0D;\n\n    /**\n     * Datagrams with errors received\n     */\n    protected String inErrors = \"0\";\n    protected double inErrorsI = 0D;\n\n    /**\n     * Sent datagrams\n     */\n    protected String outDatagrams = \"0\";\n    protected double outDatagramsI = 0D;\n\n    public UDPStatistics() {\n        super();\n    }\n\n    public final void setInDatagrams(final String inDatagrams, final double inDatagramsI) {\n        this.inDatagrams = inDatagrams;\n        this.inDatagramsI = inDatagramsI;\n    }\n\n    public final String getInDatagrams() {\n        return inDatagrams;\n    }\n\n    public final double getInDatagramsI() {\n        return inDatagramsI;\n    }\n\n    public final String getInDatagramsAsString() {\n        return inDatagrams + \" datagrams received\";\n    }\n\n    public final void setNoPorts(final String noPorts, final double noPortsI) {\n        this.noPorts = noPorts;\n        this.noPortsI = noPortsI;\n    }\n\n    public final String getNoPorts() {\n        return noPorts;\n    }\n\n    public final double getNoPortsI() {\n        return noPortsI;\n    }\n\n    public final String getNoPortsAsString() {\n        return noPorts + \" datagrams to unknown port received\";\n    }\n\n    public final void setInErrors(final String inErrors, final double inErrorsI) {\n        this.inErrors = inErrors;\n        this.inErrorsI = inErrorsI;\n    }\n\n    public final String getInErrors() {\n        return inErrors;\n    }\n\n    public final double getInErrorsI() {\n        return inErrorsI;\n    }\n\n    public final String getInErrorsAsString() {\n        return inErrors + \" datagrams received with errors\";\n    }\n\n    public final void setOutDatagrams(final String outDatagrams, final double outDatagramsI) {\n        this.outDatagrams = outDatagrams;\n        this.outDatagramsI = outDatagramsI;\n    }\n\n    public final String getOutDatagrams() {\n        return outDatagrams;\n    }\n\n    public final double getOutDatagramsI() {\n        return outDatagramsI;\n    }\n\n    public final String getOutDatagramsAsString() {\n        return outDatagrams + \" datagrams sent\";\n    }\n\n    public String toString() {\n        final StringBuffer buf = new StringBuffer();\n        buf.append(\"UDP Statistics:\\n\");\n        buf.append(getInDatagramsAsString()).append(\"\\n\");\n        buf.append(getNoPortsAsString()).append(\"\\n\");\n        buf.append(getInErrorsAsString()).append(\"\\n\");\n        buf.append(getOutDatagramsAsString()).append(\"\\n\");\n        return buf.toString();\n    }\n\n} // end of class UDPStatistics\n\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/SocketFactory.java",
    "content": "/*\n * $Id$\n */\n\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport javax.net.ssl.*;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.security.KeyStore;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Factory used to create ssl server sockets. NO client authentication is done. Usefull when a password-based authentication over a secure channel is needed\n *\n * @author Adrian Muraru\n */\n\npublic class SocketFactory {\n    /**\n     * Logger name\n     */\n    private static final transient String COMPONENT = \"lisa.comm.net.TLSSocketFactory\";\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(COMPONENT);\n\n    /**\n     * maximum time to connect with the other endPoint\n     */\n    private static final int CONNECT_TIMEOUT = 15 * 1000; // 15s\n\n    public static SSLServerSocket createServerSocket(int port, String keystore, String password) throws IOException {\n        return createServerSocket(port, keystore, password, false);\n    }\n\n    /**\n     * @param port:   port to listen on\n     * @param keystore:  the path to keystore file containing server key pair (private/public key); if <code>null</code> is passed\n     * @param password: password needed to access keystore file\n     * @return a SSL Socket bound on port specified\n     * @throws IOException\n     */\n    public static SSLServerSocket createServerSocket(int port, String keystore, String password, boolean needClientAuth) throws IOException {\n        SSLServerSocketFactory ssf = null;\n        SSLServerSocket ss = null;\n\n        try {\n            SSLContext ctx;\n            KeyManagerFactory kmf;\n            KeyStore ks;\n            ctx = SSLContext.getInstance(\"TLS\");\n            kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n            ks = KeyStore.getInstance(KeyStore.getDefaultType());\n            FileInputStream is = new FileInputStream(keystore);\n            ks.load(is, password.toCharArray());\n            kmf.init(ks, password.toCharArray());\n            if (logger.isLoggable(Level.FINER))\n                logger.log(Level.FINER, \"Server keys loaded\");\n\n            ctx.init(kmf.getKeyManagers(), null, new java.security.SecureRandom());\n            ssf = ctx.getServerSocketFactory();\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"Creating SSocket\");\n            }\n            ss = (SSLServerSocket) ssf.createServerSocket();\n\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"SSocket created!\");\n            }\n\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"SSocket binding on port \" + port);\n            }\n            ss.bind(new InetSocketAddress(port));\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"SSocket bounded on port \" + port);\n            }\n            ss.setNeedClientAuth(needClientAuth);\n            // this socket will try to authenticate clients based on X.509 Certificates\n            // ss.setWantClientAuth(true);\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"SSocket FINISHED ok! Bounded on \" + port);\n            }\n\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"Got Exception\", t);\n            }\n            t.printStackTrace();\n            throw new IOException(t.getMessage());\n        }\n        return ss;\n    }\n\n    /**\n     * Creates a client socket connected to a TLS capable server - no server authentication is performed, it accept any server certificate (anonymous TLS sessions) todo, host-based\n     * authentication should be performed in future\n     *\n     * @param host\n     * @param port\n     * @return\n     * @throws IOException\n     */\n    public static Socket createClientSocket(String host, int port, boolean ssl) throws IOException {\n\n        if (!ssl) {\n            // Create a socket with a timeout\n            InetAddress addr = InetAddress.getByName(host);\n            SocketAddress sockaddr = new InetSocketAddress(addr, port);\n            // Create an unbound socket\n            Socket sock = new Socket();\n            // This method will block no more than timeoutMs.\n            // If the timeout occurs, SocketTimeoutException is thrown.\n            int timeoutMs = 2000; // 2 seconds\n            sock.connect(sockaddr, timeoutMs);\n            return sock;\n        }\n\n        // Create a trust manager that does not validate certificate chains\n        TrustManager[] trustAllCertsTM = new TrustManager[]{new X509TrustManager() {\n            public java.security.cert.X509Certificate[] getAcceptedIssuers() {\n                return new java.security.cert.X509Certificate[0];\n            }\n\n            public void checkClientTrusted(@SuppressWarnings(\"unused\")\n                                                   java.security.cert.X509Certificate[] certs, @SuppressWarnings(\"unused\")\n                                                   String authType) {\n            }\n\n            public void checkServerTrusted(@SuppressWarnings(\"unused\")\n                                                   java.security.cert.X509Certificate[] certs, @SuppressWarnings(\"unused\")\n                                                   String authTsype) {\n            }\n        }};\n\n        SSLSocketFactory factory = null;\n        SSLContext ctx;\n\n        try {\n            ctx = SSLContext.getInstance(\"TLS\");\n            ctx.init(null, trustAllCertsTM, null);\n            factory = ctx.getSocketFactory();\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n\n        SSLSocket socket = (SSLSocket) factory.createSocket();\n        socket.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT);\n        return socket;\n    }\n\n    /**\n     * Create an SSL client socket that will provide authentication for itself based on the supplied keystore\n     *\n     * @param host\n     * @param port\n     * @param keystore\n     * @param password\n     * @return\n     * @throws IOException\n     */\n    public static Socket createAuthClientSocket(String host, int port, String keystore, String password) throws IOException {\n\n        // Create a trust manager that does not validate certificate chains\n        TrustManager[] trustAllCertsTM = new TrustManager[]{new X509TrustManager() {\n            public java.security.cert.X509Certificate[] getAcceptedIssuers() {\n                return new java.security.cert.X509Certificate[0];\n            }\n\n            public void checkClientTrusted(@SuppressWarnings(\"unused\")\n                                                   java.security.cert.X509Certificate[] certs, @SuppressWarnings(\"unused\")\n                                                   String authType) {\n            }\n\n            public void checkServerTrusted(@SuppressWarnings(\"unused\")\n                                                   java.security.cert.X509Certificate[] certs, @SuppressWarnings(\"unused\")\n                                                   String authTsype) {\n            }\n        }};\n\n        SSLSocketFactory factory = null;\n        SSLContext ctx;\n\n        try {\n            KeyManagerFactory kmf;\n            KeyStore ks;\n            ctx = SSLContext.getInstance(\"TLS\");\n            kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n            ks = KeyStore.getInstance(KeyStore.getDefaultType());\n            FileInputStream is = new FileInputStream(keystore);\n            ks.load(is, password.toCharArray());\n            kmf.init(ks, password.toCharArray());\n            ctx.init(kmf.getKeyManagers(), trustAllCertsTM, null);\n            factory = ctx.getSocketFactory();\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n\n        SSLSocket socket = (SSLSocket) factory.createSocket();\n        socket.connect(new InetSocketAddress(host, port), CONNECT_TIMEOUT);\n        return socket;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRClient.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.IOException;\n\n/**\n * java implementation of XDR Client. extends\n *\n * @author Lucian Musat\n */\npublic final class XDRClient extends XDRTcpSocket {\n\n    /** state of xdr connection * */\n    // private int state = NO_STATE;\n    // public static final int NO_STATE = 0;\n    // public static final int STATE_INIT = 1;\n    // public static final int STATE_SESSION = 2;\n    // public static final int STATE_CLOSED = 3;\n    /**\n     * puts the xdr session in wait mode because it is not used, at least not yet\n     */\n    private Object waitObj = new Object();\n    /**\n     * if should wait on the wait object or not\n     */\n    private volatile boolean bWait = true;\n\n    protected XDRClient(String sHost, int nPort) throws IOException {\n        super(SocketFactory.createClientSocket(sHost, nPort, false));\n    }\n\n    protected XDRClient(String sHost, int nPort, boolean ssl) throws IOException {\n        super(SocketFactory.createClientSocket(sHost, nPort, ssl));\n    }\n\n    /**\n     * creates a new client connection with the xdr lisa server\n     *\n     * @param sHost hostname of lisa\n     * @param nPort port on which the xdr daemon listens\n     * @return new xdr client or null if it could not be created or started\n     */\n    public static XDRClient getClient(String sHost, int nPort, boolean ssl) {\n        XDRClient cl = null;\n        try {\n            cl = new XDRClient(sHost, nPort, ssl);\n            new Thread(cl).start();\n        } catch (IOException e) {\n            e.printStackTrace();\n            cl = null;\n        }\n        return cl;\n    }\n\n    public static XDRClient getClient(String sHost, int nPort) {\n        return getClient(sHost, nPort, false);\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        if (args.length < 2) {\n            System.err.println(\"Too few parameters.\\nUsage: <xdr_client> <host> <port>\");\n            System.exit(-1);\n        }\n        int nPort = 0;\n        try {\n            nPort = Integer.parseInt(args[1]);\n        } catch (Exception ex) {\n            System.err.println(\"Invalid port number.\\nUsage: <xdr_client> <host> <port>\");\n            System.exit(-1);\n        }\n        try {\n            new Thread(new XDRClient(args[0], nPort)).start();\n        } catch (IOException e) {\n            e.printStackTrace();\n            System.exit(-1);\n        }\n    }\n\n    @Override\n    protected void initSession() throws Exception {\n        // TODO do authentication\n        System.out.println(\"Init connection\");\n        // state = STATE_INIT;\n    }\n\n    @Override\n    protected void xdrSession() throws Exception {\n        // TODO do xdr session: exchange of information, main loop\n        System.out.println(\"XDR session started\");\n        // state = STATE_SESSION;\n        if (bWait) {\n            try {\n                synchronized (waitObj) {\n                    waitObj.wait();\n                }\n            } catch (InterruptedException ex) {\n\n            }\n        }\n        System.out.println(\"XDR session ended\");\n    }\n\n    public void close() {\n        super.close();\n        // notify the xdr session that should finish\n        // why here and not in notify... is because the notify will be called after xdrSession ends\n        bWait = false;\n        synchronized (waitObj) {\n            waitObj.notify();\n        }\n    }\n\n    @Override\n    protected void notifyXDRCommClosed() {\n        // TODO this end was just notified of connection closed\n        System.out.println(\"Connection closed\");\n        // state = STATE_CLOSED;\n    }\n\n    synchronized public String sendCommand(String sCommand) throws Exception {\n        XDRMessage msg = XDRMessage.getSuccessMessage(sCommand);\n        XDRMessage resMsg = null;\n        write(msg);\n        resMsg = read();\n\n        if (resMsg == null)\n            throw new Exception(\"no connection!!!\");\n        if (resMsg.status == XDRMessage.ERROR)\n            throw new Exception(resMsg.payload);\n\n        return resMsg.payload;\n    }\n\n    public boolean isClosed() {\n        return super.closed;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRDataInput.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.DataInput;\nimport java.io.IOException;\n\n\n/**\n * An interface implemented by input streams that support XDR.\n * <p>\n * The XDR format is almost identical to the normal Java DataInput\n * format, except that items are padded to 4 byte boundaries, and\n * strings are normally stored in ASCII format.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic interface XDRDataInput extends DataInput {\n    /**\n     * Skips appropriate amount to bring stream to 4-byte boundary.\n     */\n    void pad() throws IOException;\n\n    /**\n     * Reads a double array. Assumes int length proceeds array.\n     * Throws an exception if array length > 32767 to protect\n     * against bad data exhausting memory. If buffer is not null,\n     * and is large enough to hold array, it is filled and returned,\n     * otherwise a new array is allocated and returned.\n     */\n    double[] readDoubleArray(double[] buffer) throws IOException;\n\n    /**\n     * Reads a float array. Assumes int length proceeds array.\n     * Throws an exception if array length > 32767 to protect\n     * against bad data exhausting memory. If buffer is not null,\n     * and is large enough to hold array, it is filled and returned,\n     * otherwise a new array is allocated and returned.\n     */\n    float[] readFloatArray(float[] buffer) throws IOException;\n\n    /**\n     * Reads an integer array. Assumes int length proceeds array.\n     * Throws an exception if array length > 32767 to protect\n     * against bad data exhausting memory. If buffer is not null,\n     * and is large enough to hold array, it is filled and returned,\n     * otherwise a new array is allocated and returned.\n     */\n    int[] readIntArray(int[] buffer) throws IOException;\n\n    /**\n     * Read a String. Assumes int length proceeds String.\n     * Throws an exception if string length > 32767 to protect\n     * against bad data exhausting memory.\n     */\n    String readString() throws IOException;\n\n    /**\n     * Reads a String of length l bytes, and skips appropriate\n     * amount to bring stream to 4-byte boundary.\n     */\n    String readString(int l) throws IOException;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRDataOutput.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.DataOutput;\nimport java.io.IOException;\n\n\n/**\n * An interface implemented by output streams that support XDR.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic interface XDRDataOutput extends DataOutput {\n    void pad() throws IOException;\n\n    void writeDoubleArray(double[] array) throws IOException;\n\n    void writeDoubleArray(double[] array, int start, int n) throws IOException;\n\n    void writeFloatArray(float[] array) throws IOException;\n\n    void writeFloatArray(float[] array, int start, int n) throws IOException;\n\n    void writeIntArray(int[] array) throws IOException;\n\n    void writeIntArray(int[] array, int start, int n) throws IOException;\n\n    /**\n     * Write a string preceeded by its (int) length\n     */\n    void writeString(String string) throws IOException;\n\n    /**\n     * Write a string (no length is written)\n     */\n    void writeStringChars(String string) throws IOException;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRGenericComm.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * @author Adrian Muraru\n */\npublic abstract class XDRGenericComm\n        implements Runnable {\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(XDRGenericComm.class.getName());\n    private static long keys;\n    private static Object keyLock;\n\n    static {\n        keyLock = new Object();\n        synchronized (keyLock) {\n            keys = 0;\n        }\n    }\n\n    protected XDRInputStream xdris;\n    protected XDROutputStream xdros;\n    protected boolean closed;\n    //XDRSessionHandler sessionHandler;\n    String myName;\n    private String key;\n\n    public XDRGenericComm(String myName, XDROutputStream xdros, XDRInputStream xdris, boolean closed) {\n        //this.sessionHandler = sessionHandler;\n        setMyName(myName);\n        this.xdris = xdris;\n        this.xdros = xdros;\n        this.closed = closed;\n        key = null;\n\n    }\n\n    public XDRGenericComm(String myName, XDROutputStream xdros, XDRInputStream xdris) {\n        this(myName, xdros, xdris, false);\n    }\n\n\n    public XDRGenericComm(String myName) {\n        this(myName, null, null, true);\n    }\n\n    private static String nextKey() {\n        synchronized (keyLock) {\n            return \"\" + keys++;\n        }\n    }\n\n    /**\n     * Called just before the session start\n     * Can be used for authentication\n     *\n     * @throws {@link Exception}\n     *                if comm. session could not be established\n     */\n    protected abstract void initSession() throws Exception;\n\n    /**\n     * XDR Session protocol\n     *\n     * @throws {@link Exception}\n     *                if session is broken and it should be closed\n     */\n    protected abstract void xdrSession() throws Exception;\n\n    /**\n     * Called just before the session closing. Should be used to do upper-layers\n     * cleanups\n     */\n    protected abstract void notifyXDRCommClosed();\n\n    public void run() {\n        try {\n            initSession();\n        } catch (Exception e) {\n            if (logger.isLoggable(Level.WARNING))\n                logger.log(Level.WARNING, \"Session [\" + System.currentTimeMillis() + \" ] \" + myName + \" K: [\" + getKey() + \"] cannot be initialized..closing\", e);\n            notifyXDRCommClosed();\n            close();\n            return;\n        }\n        // else: session successfully init'ed ...enter main loop\n        if (logger.isLoggable(Level.FINE))\n            logger.log(Level.FINE, \" [ \" + System.currentTimeMillis() + \" ] \" + getMyName() + \" enter main-loop. \");\n\n        try {\n                /*\n\t\t\t\t * XDRMessage xdrMsg = read(); if (xdrMsg == null) continue;\n\t\t\t\t * notifier.notifyXDRMessage(xdrMsg, this);\n\t\t\t\t */\n            xdrSession();\n        } catch (Throwable t) {\n\n            if (logger.isLoggable(Level.WARNING))\n                logger.log(Level.WARNING, \" [ \" + System.currentTimeMillis() + \" ] \" + getMyName() + \" is broken. Closing it.. \");\n\n            StringWriter sw = new StringWriter();\n            t.printStackTrace(new PrintWriter(sw));\n            XDRMessage msg = XDRMessage.getErrorMessage(sw.getBuffer().toString());\n            try {\n                write(msg);\n            } catch (Throwable tsend) {\n            }\n        }\n\n        notifyXDRCommClosed();\n        if (logger.isLoggable(Level.INFO))\n            logger.log(Level.INFO, \" [ \" + System.currentTimeMillis() + \" ] \" + myName + \" K: [\" + getKey() + \"] exits now .... \\n\\n\");\n        close();\n    }\n\n    public XDRMessage read() throws IOException {\n        try {\n            XDRMessage msg = new XDRMessage();\n            msg.xdrMessageSize = xdris.readInt();\n            xdris.pad();\n            msg.status = xdris.readInt();\n            xdris.pad();\n            msg.payload = xdris.readString();\n            xdris.pad();\n            return msg;\n        } catch (java.io.EOFException eofe) {\n            logger.log(Level.INFO, \" [ \" + System.currentTimeMillis() + \" ] \" + getMyName() + \": Connection closed by remote host\");\n            throw new IOException(\" [ \" + System.currentTimeMillis() + \" ] \" + getMyName() + \": Connection closed by remote host\");\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINEST))\n                logger.log(Level.FINEST, \"XDR Read Error: Cause:\", t);\n            else if (logger.isLoggable(Level.WARNING))\n                logger.log(Level.WARNING, \"XDR Read Error. Cause:[\" + t.getMessage() + \"]\");\n            throw new IOException(\"XDR Read Error: [\" + t.getMessage() + \"]\");\n        }\n    }\n\n    public synchronized void write(XDRMessage msg) throws IOException {\n        try {\n            msg.xdrMessageSize = getXDRSize(msg);\n\n            xdros.writeInt(msg.xdrMessageSize);\n            xdros.pad();\n            xdros.writeInt(msg.status);\n            xdros.pad();\n            xdros.writeString(msg.payload);\n            xdros.pad();\n            xdros.flush();\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINEST))\n                logger.log(Level.FINEST, \"XDR Write Error\", t);\n            else if (logger.isLoggable(Level.WARNING))\n                logger.log(Level.WARNING, \"XDR Write Error. Cause:[\" + t.getMessage() + \"]\");\n            throw new IOException(\"XDR Write error: [\" + t.getMessage() + \"]\");\n        }\n    }\n\n    public void close() {\n        if (!closed) {// allow multiple invocation for close()\n            closed = true;\n            try {\n                if (xdris != null)\n                    xdris.close();\n                if (xdros != null)\n                    xdros.close();\n            } catch (Throwable t) {\n\n            }\n        }\n    }\n\n    public String getKey() {\n        if (key == null) {\n            key = nextKey();\n        }\n        return key;\n    }\n\n    private int getXDRSize(String data) {\n        int size = 0;\n        if (data != null && data.length() != 0) {\n            size = data.length() + 4;\n\t\t\t/*\n\t\t\t * the length of the XDR representation must be a multiple of 4, so\n\t\t\t * there might be some extra bytes added\n\t\t\t */\n            if (size % 4 != 0)\n                size += (4 - size % 4);\n        }\n        return size;\n    }\n\n    private int getXDRSize(XDRMessage msg) {\n        int size = 8; // two integers (size and status)\n        size += getXDRSize(msg.payload);\n        return size;\n    }\n\n    /**\n     * @return the friendly name of this communication endpoint\n     */\n    public String getMyName() {\n        return this.myName;\n    }\n\n    /**\n     * @param myName: communication endpoint friendly name\n     */\n    public void setMyName(String myName) {\n        this.myName = myName;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRInputStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.*;\n\n\n/**\n * A class for reading XDR files. Not too hard to do in Java since the XDR format is very\n * similar to the Java native DataStream format, except for String and the fact that elements\n * (ro an array of elements) are always padded to a multiple of 4 bytes.\n * <p>\n * This class requires the user to call the pad method, to skip to the next\n * 4-byte boundary after reading an element or array of elements that may not\n * span a multiple of 4 bytes.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic class XDRInputStream extends DataInputStream implements XDRDataInput {\n    private CountedInputStream cin;\n\n    public XDRInputStream(InputStream in) {\n        super(new CountedInputStream(in));\n        cin = (CountedInputStream) this.in;\n    }\n\n    public long getBytesRead() {\n        return cin.getBytesRead();\n    }\n\n    /**\n     * Sets a limit on the number of bytes that can be read from this file\n     * before an EOF will be generated\n     */\n    public void setReadLimit(int bytes) {\n        cin.setReadLimit(bytes);\n    }\n\n    public void clearReadLimit() {\n        cin.clearReadLimit();\n    }\n\n    /**\n     * Skips appropriate amount to bring stream to 4-byte boundary.\n     */\n    public void pad() throws IOException {\n        int offset = (int) (getBytesRead() % 4);\n        if (offset != 0)\n            skipBytes(4 - offset);\n    }\n\n    public double[] readDoubleArray(double[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        double[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new double[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readDouble();\n        return result;\n    }\n\n    public float[] readFloatArray(float[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        float[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new float[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readFloat();\n        return result;\n    }\n\n    public int[] readIntArray(int[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        int[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new int[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readInt();\n        return result;\n    }\n\n    public String readString(int l) throws IOException {\n        byte[] ascii = new byte[l];\n        readFully(ascii);\n        pad();\n        return new String(ascii); //BUG: what is default locale is not US-ASCII\n    }\n\n    public String readString() throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n        return readString(l);\n    }\n\n    private static final class CountedInputStream extends BufferedInputStream {\n        private long bcount = 0;\n        private long limit = -1;\n        private long mark = 0;\n\n        CountedInputStream(InputStream in) {\n            super(in);\n        }\n\n        public long getBytesRead() {\n            return bcount;\n        }\n\n        public int available() throws IOException {\n            return Math.min((int) (limit - bcount), super.available());\n        }\n\n        public synchronized void mark(int readlimit) {\n            mark = bcount;\n            super.mark(readlimit);\n        }\n\n        public int read() throws IOException {\n            int available = checkLimit(1);\n            int rc = super.read();\n            if (rc >= 0)\n                bcount++;\n            return rc;\n        }\n\n        public int read(byte[] data) throws IOException {\n            return read(data, 0, data.length);\n        }\n\n        public int read(byte[] data, int off, int len) throws IOException {\n            int available = checkLimit(len);\n            int rc = super.read(data, off, available);\n            if (rc > 0)\n                bcount += rc;\n            return rc;\n        }\n\n        public synchronized void reset() throws IOException {\n            bcount = mark;\n            super.reset();\n        }\n\n        public long skip(long bytes) throws IOException {\n            long available = checkLimit(bytes);\n            long rc = super.skip(available);\n            if (rc > 0)\n                bcount += rc;\n            return rc;\n        }\n\n        /**\n         * Sets a limit on the number of bytes that can be read from this file\n         * before an EOF will be generated\n         */\n        void setReadLimit(int bytes) {\n            limit = bcount + bytes;\n        }\n\n        void clearReadLimit() {\n            limit = -1;\n        }\n\n        private int checkLimit(int request) throws IOException {\n            if (limit < 0)\n                return request;\n            else if (limit <= bcount)\n                throw new EOFException();\n            return Math.min(request, (int) (limit - bcount));\n        }\n\n        private long checkLimit(long request) throws IOException {\n            if (limit < 0)\n                return request;\n            else if (limit <= bcount)\n                throw new EOFException();\n            return Math.min(request, limit - bcount);\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRMLMappings.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\n/**\n * @author ramiro\n */\npublic final class XDRMLMappings {\n    public static final int XDR_STRING = 0;\n    public static final int XDR_INT16 = 1;\n    public static final int XDR_INT32 = 2;\n    public static final int XDR_INT64 = 3;\n    public static final int XDR_REAL32 = 4;\n    public static final int XDR_REAL64 = 5;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRMessage.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\n/**\n * XDR message used by LisaDaemon and different API libraries\n *\n * @author Adrian Muraru\n */\npublic class XDRMessage {\n\n    public static final int SUCCESS = 0;\n    public static final int ERROR = 1;\n    public int status;\n    public String payload;\n    protected int xdrMessageSize;\n\n    /**\n     * constructs a xdr message containing a text and default status of SUCCESS xdrMessageSize remains uninitialized\n     *\n     * @param msg\n     * @return\n     */\n    public static final XDRMessage getSuccessMessage(String msg) {\n        XDRMessage m = new XDRMessage();\n        m.payload = msg;\n        m.status = SUCCESS;\n\n        return m;\n    }\n\n    /**\n     * constructs a xdr message containing a text and default message tag xdrMessageSize remains uninitialized\n     *\n     * @param msg\n     * @return\n     */\n    public static final XDRMessage getMessage(String msg, int tag) {\n        XDRMessage m = new XDRMessage();\n        m.payload = msg;\n        m.status = tag;\n        return m;\n    }\n\n    public static final XDRMessage getErrorMessage(String cause) {\n        XDRMessage retMsg = new XDRMessage();\n        retMsg.payload = cause;\n        retMsg.status = ERROR;\n        return retMsg;\n    }\n\n    public static final XDRMessage getErrorMessage(Throwable t) {\n        StringWriter sw = new StringWriter();\n        t.printStackTrace(new PrintWriter(sw));\n        return getErrorMessage(sw.getBuffer().toString());\n    }\n\n    public String toString() {\n        return \"[\" + (status == SUCCESS ? \"SUCCESS\" : status == ERROR ? \"ERROR\" : String.valueOf(status)) + \"] \" + payload;\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRMessageNotifier.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\n/**\n * @author Adrian Muraru\n */\npublic interface XDRMessageNotifier {\n    public void notifyXDRMessage(XDRMessage message, XDRGenericComm comm);\n\n    public void notifyXDRCommClosed(XDRGenericComm comm);\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRNamedPipe.java",
    "content": "/*\n * Created on Jun 20, 2006\n * \n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\n/**\n * @author Adrian Muraru\n */\npublic class XDRNamedPipe extends XDRGenericComm {\n\n    protected File pipeIn;\n    protected File pipeOut;\n\n    public XDRNamedPipe(String pipeNameIn, String pipeNameOut) throws IOException {\n        super(\"XDRNamedPipe for [ \" + pipeNameIn + \" - \" + pipeNameOut + \" ] \", new XDROutputStream(new FileOutputStream(new File(pipeNameOut))), new XDRInputStream(\n                new FileInputStream(new File(pipeNameIn))));\n    }\n\n    //create a pipe (not open by default)\n    public XDRNamedPipe(File pipeIn, File pipeOut) {\n        super(\"XDRNamedPipe for [ \" + pipeIn + \" - \" + pipeOut + \" ] \");\n        this.pipeIn = pipeIn;\n        this.pipeOut = pipeOut;\n    }\n\n    @Override\n    protected void initSession() throws Exception {\n        this.xdris = new XDRInputStream(new FileInputStream(this.pipeIn));\n        this.xdros = new XDROutputStream(new FileOutputStream(pipeOut));\n        super.closed = false;\n    }\n\n    @Override\n    protected void notifyXDRCommClosed() {\n\n    }\n\n    @Override\n    protected void xdrSession() throws Exception {\n        // nothing to do on pipes\n\n    }\n\n}"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDROutputStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.DataOutputStream;\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * A class for writing XDR files. Not too hard to do in Java since the XDR format is very\n * similar to the Java native DataStream format, except for String and the fact that elements\n * (ro an array of elements) are always padded to a multiple of 4 bytes.\n * <p>\n * This class requires the user to call the pad method, to skip to the next\n * 4-byte boundary after writing an element or array of elements that may not\n * span a multiple of 4 bytes.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic class XDROutputStream extends DataOutputStream implements XDRDataOutput {\n    private final static byte[] padding =\n            {0, 0, 0, 0};\n    private CountedOutputStream cout;\n\n    public XDROutputStream(OutputStream out) {\n        super(new CountedOutputStream(out));\n        cout = (CountedOutputStream) this.out;\n    }\n\n    public void writeString(String s) throws IOException {\n        writeInt(s.length());\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n\n    public void writeStringChars(String s) throws IOException {\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n\n    public void writeIntArray(int[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeInt(array[i]);\n    }\n\n    public void writeIntArray(int[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeInt(array[i]);\n    }\n\n    public void writeDoubleArray(double[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeDouble(array[i]);\n    }\n\n    public void writeDoubleArray(double[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeDouble(array[i]);\n    }\n\n    public void writeFloatArray(float[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++) writeFloat(array[i]);\n    }\n\n    public void writeFloatArray(float[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++) writeFloat(array[i]);\n    }\n\n    /**\n     * Skips appropriate amount to bring stream to 4-byte boundary.\n     */\n    public void pad() throws IOException {\n        int offset = (int) (getBytesWritten() % 4);\n        if (offset != 0) write(padding, 0, 4 - offset);\n    }\n\n    public long getBytesWritten() {\n        return cout.getBytesWritten();\n    }\n\n    private static final class CountedOutputStream extends FilterOutputStream {\n        private long count = 0;\n\n        CountedOutputStream(OutputStream out) {\n            super(out);\n        }\n\n        public void write(int b) throws IOException {\n            out.write(b);\n            count++;\n        }\n\n        public void write(byte[] data) throws IOException {\n            out.write(data);\n            count += data.length;\n        }\n\n        public void write(byte[] data, int off, int len) throws IOException {\n            out.write(data, off, len);\n            count += len;\n        }\n\n        public long getBytesWritten() {\n            return count;\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRRandomAccessFile.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\n\n/**\n * A random access file for use with XDR.\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic class XDRRandomAccessFile extends RandomAccessFile implements XDRDataInput, XDRDataOutput {\n    public XDRRandomAccessFile(String name, String mode) throws IOException {\n        super(name, mode);\n    }\n\n    public void pad() throws IOException {\n        int offset = (int) (getFilePointer() % 4);\n        if (offset != 0)\n            skipBytes(4 - offset);\n    }\n\n    public double[] readDoubleArray(double[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        double[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new double[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readDouble();\n        return result;\n    }\n\n    public float[] readFloatArray(float[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        float[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new float[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readFloat();\n        return result;\n    }\n\n    public int[] readIntArray(int[] buffer) throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n\n        int[] result = buffer;\n        if ((buffer == null) || (l > buffer.length))\n            result = new int[l];\n        for (int i = 0; i < l; i++)\n            result[i] = readInt();\n        return result;\n    }\n\n    public String readString(int l) throws IOException {\n        byte[] ascii = new byte[l];\n        readFully(ascii);\n        pad();\n        return new String(ascii); //BUG: what is default locale is not US-ASCII\n    }\n\n    public String readString() throws IOException {\n        int l = readInt();\n        if (l > 32767)\n            throw new IOException(\"String too long: \" + l);\n        return readString(l);\n    }\n\n    public void writeDoubleArray(double[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++)\n            writeDouble(array[i]);\n    }\n\n    public void writeDoubleArray(double[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++)\n            writeDouble(array[i]);\n    }\n\n    public void writeFloatArray(float[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++)\n            writeFloat(array[i]);\n    }\n\n    public void writeFloatArray(float[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++)\n            writeFloat(array[i]);\n    }\n\n    public void writeIntArray(int[] array) throws IOException {\n        writeInt(array.length);\n        for (int i = 0; i < array.length; i++)\n            writeInt(array[i]);\n    }\n\n    public void writeIntArray(int[] array, int start, int n) throws IOException {\n        writeInt(n);\n        for (int i = start; i < n; i++)\n            writeInt(array[i]);\n    }\n\n    public void writeString(String s) throws IOException {\n        writeInt(s.length());\n\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n\n    public void writeStringChars(String s) throws IOException {\n        byte[] ascii = s.getBytes();\n        write(ascii);\n        pad();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRSerializable.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.IOException;\n\n/**\n * An interface to be implemented by objects than\n * can be read and written using XDR\n *\n * @author Tony Johnson (tonyj@slac.stanford.edu)\n */\npublic interface XDRSerializable {\n    public void read(XDRDataInput in) throws IOException;\n\n    public void write(XDRDataOutput out) throws IOException;\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/monitoring/lisa/xdr/XDRTcpSocket.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.monitoring.lisa.xdr;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.util.logging.Logger;\n\n/**\n * @author Adrian Muraru\n */\npublic abstract class XDRTcpSocket\n        extends XDRGenericComm {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(\"lisa.comm.XDRTcpSocket\");\n    protected boolean closed;\n    private Socket rawSocket;\n\n/*\tpublic static final int SERVER_MODE = 0;\n    public static final int CLIENT_MODE = 1;\n\tprivate int mode = CLIENT_MODE;\n*/\n\n\n    public XDRTcpSocket(Socket s) throws IOException {\n        super(\"XDRTcpSocket for [ \" + s.getInetAddress() + \":\" + s.getPort() + \" ] \", new XDROutputStream(s.getOutputStream()), new XDRInputStream(s.getInputStream()));\n        this.rawSocket = s;\n        closed = false;\n\t\t/*this.mode = mode;\n\t\tthis.auth = auth;*/\n    }\n\n\t/*@Override\n\tprotected void initSession() throws Exception {\n\t\tif (auth == null ) {\n\t\t\tif (logger.isLoggable(Level.WARNING))\n\t\t\t\tlogger.log(Level.WARNING, \" No Authenticator in place.... We'll not perform authentication phase\");\n\t\t\treturn;\n\t\t}\n\t\tif (mode == SERVER_MODE)\n\t\t\tauth.acceptSession(rawSocket);\n\t\telse\n\t\t\tauth.initSession(rawSocket);\n\t}*/\n\n    public int getPort() {\n        return rawSocket.getPort();\n    }\n\n    public int getLocalPort() {\n        return rawSocket.getLocalPort();\n    }\n\n    public InetAddress getInetAddress() {\n        return rawSocket.getInetAddress();\n    }\n\n    public InetAddress getLocalAddress() {\n        return rawSocket.getLocalAddress();\n    }\n\n    public void close() {\n        try {\n            super.close();\n            if (!closed) {// allow multiple invocation for close()\n                closed = true;\n                if (rawSocket != null) {\n                    rawSocket.close();\n                }\n            }\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/ControlChannel.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.gsi.GSIServer;\nimport lia.gsi.net.GSIGssSocketFactory;\nimport lia.util.net.common.*;\n\nimport javax.security.auth.Subject;\nimport java.io.*;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Encapsulates the control socket ( channel ) between two peer FDTSessios When the constructor returns the\n * communication can begin ...\n *\n * @author ramiro\n */\npublic class ControlChannel extends AbstractFDTCloseable implements Runnable {\n\n    public static final int CONNECT_TIMEOUT = 20 * 1000;\n    public static final int SOCKET_TIMEOUT = 60 * 1000;\n    public static final int MAX_RETRIES = 1000;\n    public static final int RETRY_TIMEOUT = 300;\n    private static final Logger logger = Logger.getLogger(ControlChannel.class.getName());\n    private static final CtrlMsg versionMsg = new CtrlMsg(CtrlMsg.PROTOCOL_VERSION, Config.FDT_FULL_VERSION + \"-\"\n            + Config.FDT_RELEASE_DATE);\n    private static final Config config = Config.getInstance();\n    public final InetAddress remoteAddress;\n    public final int remotePort;\n    public final int localPort;\n    private final Socket controlSocket;\n    private final ConcurrentLinkedQueue<Object> qToSend = new ConcurrentLinkedQueue<Object>();\n    private final AtomicBoolean cleanupFinished = new AtomicBoolean(false);\n    private final ControlChannelNotifier notifier;\n    public Map<String, Object> remoteConf;\n    public volatile Subject subject;\n    private UUID fdtSessionID;\n    private volatile ObjectOutputStream oos = null;\n    private volatile ObjectInputStream ois = null;\n    private volatile String fullRemoteVersion;\n    private volatile String myName;\n\n    private volatile ScheduledFuture<?> ccptFuture;\n\n    /**\n     * Try to connect to a remote FDT instance\n     *\n     * @param address\n     * @param port\n     * @param sessionID\n     * @param notifier\n     * @throws Exception\n     */\n    public ControlChannel(String address, int port, UUID sessionID, ControlChannelNotifier notifier) throws Exception {\n        this(InetAddress.getByName(address), port, sessionID, notifier);\n    }\n\n    /**\n     * Try to connect to a remote FDT instance\n     *\n     * @param inetAddress\n     * @param port\n     * @param fdtSessionID\n     * @param notifier\n     * @throws Exception\n     */\n    public ControlChannel(InetAddress inetAddress, int port, UUID fdtSessionID, ControlChannelNotifier notifier)\n            throws Exception {\n        try {\n            this.notifier = notifier;\n            this.fdtSessionID = fdtSessionID;\n\n            if (config.isGSIModeEnabled()) {\n                GSIGssSocketFactory factory = new GSIGssSocketFactory();\n                controlSocket = factory.createSocket(inetAddress, config.getGSIPort(), false, false);\n                this.subject = GSIGssSocketFactory.getLocalSubject(controlSocket);\n            } else {\n                controlSocket = new Socket();\n                controlSocket.connect(new InetSocketAddress(inetAddress, port), CONNECT_TIMEOUT);\n            }\n\n            this.remoteAddress = inetAddress;\n            this.remotePort = port;\n            this.localPort = controlSocket.getLocalPort();\n\n            controlSocket.setTcpNoDelay(true);\n\n            // only the first socket will be interpreted by the AcceptTask at the other end\n            if (!config.isGSIModeEnabled()) {\n                controlSocket.getOutputStream().write(new byte[]{0});\n            }\n\n            // from now on only CtrlMsg will be sent\n            initStreams();\n            controlSocket.setSoTimeout(1000);\n\n        } catch (Throwable t) {\n            close(\"Cannot instantiate ControlChannel\", t);\n            throw new Exception(t);\n        }\n    }\n\n    /**\n     * A remote peer connected to FDT\n     *\n     * @param s - the socket\n     * @throws Exception - if anything goes wrong in intialization\n     */\n    public ControlChannel(Socket s, ControlChannelNotifier notifier) throws Exception {\n        try {\n            this.controlSocket = s;\n\n            this.remoteAddress = s.getInetAddress();\n            this.remotePort = s.getPort();\n            this.localPort = s.getLocalPort();\n\n            this.notifier = notifier;\n\n            initStreams();\n            controlSocket.setTcpNoDelay(true);\n            controlSocket.setSoTimeout(1000);\n\n        } catch (Throwable t) {\n            close(\"Cannot instantiate ControlChannel\", t);\n            throw new Exception(t);\n        }\n    }\n\n    /**\n     * @param parent\n     */\n    public ControlChannel(GSIServer parent, Socket s, Subject peerSubject, ControlChannelNotifier notifier)\n            throws Exception {\n        try {\n\n            this.controlSocket = s;\n            this.subject = peerSubject;\n            this.remoteAddress = s.getInetAddress();\n            this.remotePort = s.getPort();\n            this.localPort = s.getLocalPort();\n\n            this.notifier = notifier;\n\n            initStreams();\n            controlSocket.setTcpNoDelay(true);\n            controlSocket.setSoTimeout(1000);\n\n        } catch (Throwable t) {\n            close(\"Cannot instantiate ControlChannel\", t);\n            throw new Exception(t);\n        }\n    }\n\n    public boolean isSocketClosed() {\n        return (this.controlSocket == null) ? true : controlSocket.isClosed();\n    }\n\n    public UUID fdtSessionID() {\n        return fdtSessionID;\n    }\n\n    @Override\n    public String toString() {\n        return (controlSocket == null) ? \"null\" : controlSocket.toString();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void initStreams() throws Exception {\n        oos = new ObjectOutputStream(new BufferedOutputStream(controlSocket.getOutputStream()));\n        sendMsgImpl(versionMsg);\n\n        try {\n            BufferedInputStream bis = new BufferedInputStream(controlSocket.getInputStream());\n            if (bis.available() == 1) {\n                throw new IllegalStateException(\"Could not initialise stream to server, client did not use GSI\");\n            } else {\n                ois = new ObjectInputStream(new BufferedInputStream(controlSocket.getInputStream()));\n            }\n        } catch (IOException ex) {\n            logger.log(Level.WARNING, \"Could not initialise stream to server, check if server is running or certificates present\" + ex);\n            throw ex;\n        }\n\n        // wait for remote version\n        CtrlMsg ctrlMsg = (CtrlMsg) ois.readObject();\n        if (ctrlMsg.tag != CtrlMsg.PROTOCOL_VERSION) {\n            throw new FDTProcolException(\"Unexpected remote control message. Expected PROTOCOL_VERSION tag [ \"\n                    + CtrlMsg.PROTOCOL_VERSION + \" ] Received tag: \" + ctrlMsg.tag);\n        }\n\n        this.fullRemoteVersion = (String) ctrlMsg.message;\n\n        ctrlMsg = new CtrlMsg(CtrlMsg.INIT_FDT_CONF, Config.getInstance().getConfigMap());\n        sendMsgImpl(ctrlMsg);\n\n        // wait for remote config\n        ctrlMsg = (CtrlMsg) ois.readObject();\n        if (ctrlMsg.tag != CtrlMsg.INIT_FDT_CONF) {\n            throw new FDTProcolException(\"Unexpected remote control message. Expected INIT_FDT_CONF tag [ \"\n                    + CtrlMsg.INIT_FDT_CONF + \" ] Received tag: \" + ctrlMsg.tag);\n        }\n\n        this.remoteConf = (HashMap<String, Object>) ctrlMsg.message;\n        try {\n\n            if (DirectByteBufferPool.initInstance(Integer.parseInt((String) remoteConf.get(\"-bs\")),\n                    Config.getMaxTakePollIter())) {\n                logger.log(Level.FINER, \"The buffer pool has been initialized\");\n            } else {\n                logger.log(Level.FINER, \"The buffer pool is already initialized\");\n            }\n\n        } catch (Throwable t) {\n            throw new FDTProcolException(\"Unable to instantiate the buffer pool\", t);\n        }\n\n        if (fdtSessionID == null) {// The remote peer should send my fdtSessionID\n\n            ctrlMsg = (CtrlMsg) ois.readObject();\n            if (ctrlMsg.tag == CtrlMsg.SESSION_ID) {\n                fdtSessionID = (UUID) ctrlMsg.message;\n            } else {\n                throw new FDTProcolException(\"Unexpected remote control message. Expected SESSION_ID tag [ \"\n                        + CtrlMsg.SESSION_ID + \" ] Received tag: \" + ctrlMsg.tag);\n            }\n        } else {// I should send the ID to the remote peer\n\n            sendMsgImpl(new CtrlMsg(CtrlMsg.SESSION_ID, fdtSessionID));\n        }\n        Utils.initLogger(config.getLogLevel(), null, new Properties());\n        myName = \" ControlThread for ( \" + fdtSessionID + \" ) \" + controlSocket.getInetAddress() + \":\"\n                + controlSocket.getPort();\n        if (Utils.isTransferPort(localPort)) {\n            config.registerTransferPortForSession(localPort, fdtSessionID.toString());\n        }\n        logger.log(Level.INFO, \"NEW CONTROL stream for \" + fdtSessionID + \" initialized \");\n\n        final long localKA = Config.getInstance().getKeepAliveDelay(TimeUnit.NANOSECONDS);\n        final String remoteKAS = (String) remoteConf.get(\"-ka\");\n        final long remoteKAN = (remoteKAS == null) ? localKA : TimeUnit.SECONDS.toNanos(Long.parseLong(remoteKAS));\n        final long remoteKA = (remoteKAN < 0) ? localKA : remoteKAN;\n\n        if ((this.fullRemoteVersion != null) && (Utils.compareVersions(this.fullRemoteVersion, \"0.9.8\") >= 0)) {\n            synchronized (this.closeLock) {\n                final FDTVersion localVersion = FDTVersion.fromVersionString(Config.FDT_FULL_VERSION + \"-\"\n                        + Config.FDT_RELEASE_DATE);\n                final FDTVersion remoteVersion = FDTVersion.fromVersionString(this.fullRemoteVersion);\n                final long kaMinNanos = Math.min(localKA, remoteKA);\n                final long kaMaxSeconds = TimeUnit.NANOSECONDS.toSeconds(kaMinNanos);\n                final String strLog = ((kaMaxSeconds > 0) ? kaMaxSeconds + \" second(s)\" : TimeUnit.NANOSECONDS\n                        .toMillis(kaMinNanos) + \" millis\");\n                logger.log(Level.INFO, \"App KeepAlive [ \" + strLog + \" ] enabled for control channel. Local \"\n                        + localVersion + \", Remote \" + remoteVersion);\n                ccptFuture = Utils.getMonitoringExecService().scheduleWithFixedDelay(\n                        new ControlChannelPingerTask(this), kaMinNanos, kaMinNanos, TimeUnit.NANOSECONDS);\n            }\n        } else {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \"[ ControlChannel ] remote version \" + fullRemoteVersion\n                        + \" does not support KEEP_ALIVE messages\");\n            }\n        }\n    }\n\n    public String remoteVersion() {\n        return fullRemoteVersion;\n    }\n\n    private final void cleanup() {\n        if (cleanupFinished.compareAndSet(false, true)) {\n            Utils.cancelFutureIgnoringException(ccptFuture, false);\n            Utils.closeIgnoringExceptions(ois);\n            if(oos != null)\n\t\t\t\ttry {\n\t\t\t\t\toos.flush();\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t}\n            Utils.closeIgnoringExceptions(oos);\n            // give the output stream time to flush\n            try {\n\t\t\t\tThread.sleep(1000);\n\t\t\t} catch (InterruptedException e) {\n\t\t\t}\n            Utils.closeIgnoringExceptions(controlSocket);\n\n            if (notifier != null) {\n                try {\n                    notifier.notifyCtrlSessionDown(this, downCause());\n                } catch (Throwable ignored) {\n                    //not interested\n                }\n            }\n        }\n    }\n\n    public void sendCtrlMessage(final CtrlMsg ctrlMsg) {\n\n        if (ctrlMsg == null) {\n            throw new NullPointerException(\"Control message cannot be null over the ControlChannel\");\n        }\n        logger.log(Level.FINER, \"[ CtrlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        qToSend.add(ctrlMsg);\n    }\n\n    public void sendSessionIDToCoordinator(CtrlMsg ctrlMsg) {\n        logger.log(Level.INFO, \"[ ControlChannel ] [ sendSessionIDToCoordinator ( \" + ctrlMsg.message.toString() + \" )\");\n        logger.log(Level.FINER, \"[ ControlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        try {\n            sendMsgImpl(ctrlMsg);\n            sendAllMsgs();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    public void sendRemoteTransferPort(CtrlMsg ctrlMsg) {\n        logger.log(Level.INFO, \"[ ControlChannel ] [ sendRemoteTransferPort ( \" + ctrlMsg.message.toString() + \" )\" + this.remoteAddress + \":\" + this.remotePort);\n        logger.log(Level.FINER, \"[ CtrlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        try {\n            sendMsgImpl(ctrlMsg);\n            sendAllMsgs();\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    public List<String> sendListFilesMessage(CtrlMsg ctrlMsg) throws IOException {\n\n        logger.log(Level.INFO, \"[ ControlChannel ] [ sendListFilesMessage ]\");\n        logger.log(Level.FINER, \"[ CtrlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        try {\n            logger.log(Level.FINEST, \"[ ControlChannel ] [ sendListFilesMessage ] sendMsgImpl \" + ctrlMsg);\n            sendMsgImpl(ctrlMsg);\n            sendAllMsgs();\n            logger.log(Level.FINEST, \"[ ControlChannel ] [ sendListFilesMessage ] waiting for response \" + ctrlMsg);\n            CtrlMsg newCtrlMsg = getResponse();\n            logger.log(Level.FINER, \"[ CtrlChannel ] [ sendListFilesMessage ] listing files on remote machine: \" + newCtrlMsg.message.toString());\n            FDTListFilesMsg msg = (FDTListFilesMsg) newCtrlMsg.message;\n            return msg.filesInDir;\n        } catch (Exception e) {\n            logger.log(Level.WARNING, \"Failed to retrieve response from server\", e);\n        }\n        cleanup();\n        return null;\n    }\n\n    public int sendTransferPortMessage(CtrlMsg ctrlMsg) throws IOException {\n\n        logger.log(Level.INFO, \"[ ControlChannel ] [ sendTransferPortMessage ]\");\n        logger.log(Level.FINER, \"[ CtrlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        try {\n            sendMsgImpl(ctrlMsg);\n            sendAllMsgs();\n            CtrlMsg newCtrlMsg = getResponse();\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"[ CtrlChannel ] [ sendTransferPortMessage ] got response: \" + newCtrlMsg.message);\n            }\n            return (Integer) newCtrlMsg.message;\n        } catch (Exception e) {\n            logger.log(Level.WARNING, \"Failed to retrieve response from server\", e);\n        }\n        cleanup();\n        return -1;\n    }\n\n    public String sendCoordinatorMessage(CtrlMsg ctrlMsg) throws IOException {\n\n        logger.log(Level.INFO, \"[ ControlChannel ] [ sendCoordinatorMessage ]\");\n        logger.log(Level.FINER, \"[ CtrlChannel ] adding to send queue msg: \" + ctrlMsg.toString());\n        if (logger.isLoggable(Level.FINEST)) {\n            Thread.dumpStack();\n        }\n        try {\n            sendMsgImpl(ctrlMsg);\n            sendAllMsgs();\n            CtrlMsg newCtrlMsg = getResponse();\n            logger.info(\"Remote job session ID: \" + newCtrlMsg.message.toString());\n            return newCtrlMsg.message.toString();\n\n        } catch (Exception e) {\n            logger.log(Level.WARNING, \"Failed to retrieve response from server\", e);\n        }\n        cleanup();\n        return null;\n    }\n\n    private CtrlMsg getResponse() throws Exception {\n        Exception t = null;\n        CtrlMsg newCtrlMsg = null;\n        logger.log(Level.FINEST, \"[ ControlChannel ] [ getResponse] will wait for response \" + (MAX_RETRIES * RETRY_TIMEOUT) + \"ms\");\n        for (int i = 1; i <= MAX_RETRIES; i++) {\n            try {\n                logger.log(Level.FINER, \"[ ControlChannel ] [ getResponse] trying to read CtrlMsg for \" + i + \" time\");\n                newCtrlMsg = (CtrlMsg) ois.readObject();\n                logger.log(Level.FINER, \"[ ControlChannel ] [ getResponse] read CtrlMsg \" + newCtrlMsg);\n                return newCtrlMsg;\n            } catch (Exception e) {\n                logger.log(Level.FINEST, \"[ ControlChannel ] [ getResponse] failed to read CtrlMsg \", e);\n                t = e;\n                Thread.sleep(RETRY_TIMEOUT);\n                logger.log(Level.FINEST, \"[ ControlChannel ] [ getResponse] waited for \" + RETRY_TIMEOUT + \"ms\");\n            } finally {\n\n                if (newCtrlMsg == null && i >= MAX_RETRIES) {\n                    logger.log(Level.FINEST, \"[ ControlChannel ] [ getResponse] CtrlMsg \" + newCtrlMsg , t);\n                    throw t;\n                }\n            }\n        }\n        logger.log(Level.FINEST, \"[ ControlChannel ] [ getResponse] got message null\");\n        return null;\n    }\n\n    public void emptyMsgQueue() throws Exception {\n        sendAllMsgs();\n    }\n\n    private synchronized void sendAllMsgs() throws Exception {\n        for (; ; ) {\n            final Object ctrlMsg = qToSend.poll();\n            if (ctrlMsg == null) {\n                break;\n            }\n            sendMsgImpl(ctrlMsg);\n        }\n    }\n\n    private void sendMsgImpl(Object o) throws Exception {\n        try {\n            logger.log(Level.INFO, \" [ ControlChannel ] sending message \" + o);\n            oos.writeObject(o);\n            oos.reset();\n            oos.flush();\n            logger.log(Level.FINER, \" [ ControlChannel ] sent message \" + o);\n        } catch (Throwable t) {\n            if (!isClosed()) {\n                close(\"Exception sending control data\", t);\n                throw new IOException(\" Cannot send ctrl message ( \" + t.getCause() + \" ) \");\n            }\n        }\n    }\n\n    @Override\n    public void run() {\n        final BlockingQueue<Object> notifQueue = new ArrayBlockingQueue<Object>(10);\n\n        // TODO - stupid hack; but gets stuck otherwise; no time to check in details ...\n        final Thread iNotif = new Thread() {\n\n            @Override\n            public void run() {\n                setName(\"INotifier for: \" + myName);\n                while ((controlSocket != null) && !controlSocket.isClosed()) {\n                    try {\n                        final Object toNotif = notifQueue.poll(1, TimeUnit.SECONDS);\n                        if (toNotif == null) {\n                            continue;\n                        }\n                        if (logger.isLoggable(Level.FINEST)) {\n                            logger.log(Level.FINEST, \"[ ControlChannel ] [ INotifier ] notifying msg: \" + toNotif);\n                        }\n                        notifier.notifyCtrlMsg(ControlChannel.this, toNotif);\n                    } catch (Throwable t) {\n                        if (logger.isLoggable(Level.FINER)) {\n                            StringBuilder sb = new StringBuilder();\n                            sb.append(\"[ ControlChannel ] [ INotifier ] Got exception. ControlChannel isClosed(): \")\n                                    .append(isClosed());\n                            if (isClosed()) {\n                                sb.append(\" downMessage: \").append(downMessage()).append(\" downCause: \")\n                                        .append(Utils.getStackTrace(downCause()));\n                            }\n                            sb.append(\" Inotifier Exception: \");\n                            logger.log(Level.FINER, sb.toString(), t);\n                        }\n                        close(\"INotifier got exception \", t);\n                        cleanup();\n                    }\n                }\n            }\n        };\n        iNotif.setDaemon(true);\n        iNotif.start();\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, myName + \" STARTED main loop\");\n        }\n\n        String internalDownMsg = null;\n        Throwable internalDownCause = null;\n\n        try {\n\n            while ((controlSocket != null) && !controlSocket.isClosed()) {\n                try {\n                    sendAllMsgs();\n                    Object o = ois.readObject();\n                    if (o == null) {\n                        continue;\n                    }\n                    final boolean isFine = logger.isLoggable(Level.FINE);\n                    if (isFine) {\n                        logger.log(Level.FINE, \" [ ControlChannel ] received msg: \" + o);\n                    }\n\n                    if (o instanceof CtrlMsg) {\n                        final CtrlMsg ctrlMsg = (CtrlMsg) o;\n                        // ping - like for the socket\n                        if (ctrlMsg.tag == CtrlMsg.KEEP_ALIVE_MSG) {\n                            if (isFine) {\n                                logger.log(Level.FINE, \"Ctrl channel received app KEEP_ALIVE_MSG\");\n                            }\n                            continue;\n                        }\n\n                        if (ctrlMsg.tag == CtrlMsg.END_SESSION_FIN2) {\n                            if (!isClosed()) {\n                                final String errMsg = \"Remote site will close the transfer session; FINAL timeout was reached. \"\n                                        + \"Most likely the TCP buffers on remote site are higher than normal. Try the blocking I/O -bio on both sides and no -ss.\";\n                                logger.log(Level.WARNING, errMsg);\n                                close(errMsg, null);\n                            }\n                            break;\n                        }\n                    }\n\n                    notifQueue.add(o);\n                } catch (SocketTimeoutException ste) {\n                \tlogger.log(Level.FINEST, \"Control Channel timeout\");\n                    // ignore this??? or shall I close it() ?\n                } catch (IOException ioe) {\n                    close(\"Control channel got I/O Exception\", ioe);\n                    cleanup();\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                    close(\"Control channel got general exception. Will close!\", t);\n                    cleanup();\n                }\n            }// main loop\n\n        } catch (Throwable t) {\n            if (!isClosed()) {\n                internalDownMsg = myName + \" got exception in main loop: \" + t.getMessage();\n                internalDownCause = t;\n\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"Control Thread for \" + myName + \" got exception in main loop\", t);\n                }\n            }\n        } finally {\n            config.releaseRemoteTransferPort(fdtSessionID.toString());\n            if ((downMessage() != null) || (downCause() != null)) {\n                close(downMessage(), downCause());\n            } else {\n                close(internalDownMsg, internalDownCause);\n            }\n            cleanup();\n        }\n\n        logger.log(Level.INFO, myName + \" FINISHED\");\n    }\n\n    @Override\n    protected void internalClose() {\n\n        try {\n            final Thread t = new Thread() {\n\n                @Override\n                public void run() {\n                    setName(\"(ML) ControlChannel Graceful stopper thread\");\n\n                    try {\n                        int retry = 0;\n\n                        while (retry++ < 3) {\n                            try {\n                                Thread.sleep(1 * 1000);\n                            } catch (Throwable ignored) {\n                                //if we're interruped - tough luck\n                            }\n\n                            try {\n                                if ((controlSocket == null) || controlSocket.isClosed()) {\n                                    break;\n                                }\n                                qToSend.add(new CtrlMsg(CtrlMsg.END_SESSION_FIN2, downMessage()\n                                        + Utils.getStackTrace(downCause())));\n                            } catch (Throwable ignored) {\n                                //if we're interruped - tough luck\n                            }\n\n                        }// end while\n\n                    } finally {\n                        cleanup();\n                    }\n                }\n            };\n\n            // if main is out ... please let me die like a real thread :)\n            t.setDaemon(true);\n            t.start();\n        } catch (Throwable ignored) {\n            // smth went dreadfully wrong ... just close the session now!\n            try {\n                cleanup();\n            } catch (Throwable exc) {\n                logger.log(Level.WARNING, \"Exception in cleanup()\", exc);\n            }\n        }\n    }\n\n    private static final class ControlChannelPingerTask implements Runnable {\n\n        public static final CtrlMsg pingMsg = new CtrlMsg(CtrlMsg.KEEP_ALIVE_MSG, new byte[1]);\n\n        private final ControlChannel cc;\n\n        ControlChannelPingerTask(ControlChannel cc) {\n            this.cc = cc;\n            logger.log(Level.INFO, \"[ ControlChannelPingerTask ] initialized\");\n        }\n\n        @Override\n        public void run() {\n\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \"[ ControlChannelPingerTask ] sending KEEP_ALIVE_MSG\");\n            }\n\n            try {\n                this.cc.sendCtrlMessage(pingMsg);\n            } catch (Throwable t) {\n                logger.log(\n                        Level.WARNING,\n                        \" [ ContrlChannelPingerTask ] Unable to send msg  ... Close the socket ??? This should not happen\",\n                        t);\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/ControlChannelNotifier.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.FDTCloseable;\n\n/**\n * Basic interface for all the classes interested in receiving the control\n * messages between the FDT peers\n *\n * @author ramiro\n */\npublic interface ControlChannelNotifier extends FDTCloseable {\n\n    public void notifyCtrlMsg(ControlChannel controlChannel, Object ctrlMessage) throws FDTProcolException;\n\n    public void notifyCtrlSessionDown(ControlChannel controlChannel, Throwable cause);\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/CtrlMsg.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport java.io.Serializable;\n\n/**\n * This class will be the only message that will be sent over the control channel\n * it will encapsulate message between two endpoint <code>FDTSession</code>-s\n *\n * @author ramiro\n */\npublic class CtrlMsg implements Serializable {\n\n    /**\n     * a ping like message used to test the connection  - at the connection Level\n     */\n    public static final int KEEP_ALIVE_MSG = 0;\n    /**\n     * message will be a string in the followinf format \"major.minor.maintenance-releaseDate\"\n     */\n    public static final int PROTOCOL_VERSION = 1;\n    /**\n     * message will be the UUID ( aka the sessionID which will be the same at both ends )\n     */\n    public static final int SESSION_ID = 2;\n    /**\n     * message will be an Short\n     */\n    public static final int SESSION_TYPE = 3;\n    /**\n     * message will be a FDTInitMsg\n     */\n    public static final int INIT_FDT_CONF = 4;\n    /**\n     * ping-like message - this is at the session LEVEL\n     */\n    public static final int PING_SESSION = 5;\n\n    //FDTSession messages\n    /**\n     * message will be a SessionConfig message\n     */\n    public static final int INIT_FDTSESSION_CONF = 6;\n\n    //From here on are ctrl messages used by the managers  \n    /**\n     * message will be a SessionConfig message\n     */\n    public static final int FINAL_FDTSESSION_CONF = 7;\n    /**\n     * message will be a SessionConfig message\n     */\n    public static final int FINISHED_FILE_SESSIONS = 8;\n    /**\n     * Notified whenever the other END is able to start\n     */\n    public static final int START_SESSION = 9;\n    /**\n     * message can be null or a String representing the cause\n     */\n    public static final int END_SESSION = 10;\n    /**\n     * message types designated to GUI\n     */\n    public static final int GUI_MSG = 11;\n    /**\n     * sent, eventually, by the FDTWriter session to notify <b>ONLY</b>\n     * the ControlChannel that it may close the socket...\n     **/\n    public static final int END_SESSION_FIN2 = 12;\n    /**\n     * message types designated for third party copy feature\n     */\n    public static final int THIRD_PARTY_COPY = 13;\n    /**\n     * message types designated for list files feature\n     */\n    public static final int LIST_FILES = 14;\n    /**\n     * message types designated for remote transfer port feature\n     */\n    public static final int REMOTE_TRANSFER_PORT = 15;\n\n    /**\n     * message types designated for informing other side about non existing file\n     */\n    public static final int FILE_NOT_FOUND = 16;\n\n\n    private static final long serialVersionUID = 6815237091777780075L;\n    private static final String[] CTRL_MSG_TAGS = new String[]{\n            \"KEEP_ALIVE_MSG\", \"PROTOCOL_VERSION\", \"SESSION_ID\", \"SESSION_TYPE\", \"INIT_FDT_CONF\", \"PING_SESSION\",\n            \"INIT_FDTSESSION_CONF\", \"FINAL_FDTSESSION_CONF\", \"FINISHED_FILE_SESSIONS\", \"START_SESSION\", \"END_SESSION\",\n            \"GUI_MSG\", \"END_SESSION_FIN2\", \"THIRD_PARTY_COPY\", \"LIST_FILES\", \"REMOTE_TRANSFER_PORT\", \"FILE_NOT_FOUND\"\n    };\n\n    /**\n     * the tag of the REQ/RESPONSE; based on this message instanceof can be avoided,\n     * though I do not think is such a big performance gain\n     */\n    public final int tag;\n\n\n    /**\n     * the message, the one and only\n     */\n    public final Object message;\n\n    public CtrlMsg(int tag, Object message) {\n        this.tag = tag;\n        this.message = message;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(\"tag ( \").append(tag).append(\" ): \");\n        if (tag < 0 || tag >= CTRL_MSG_TAGS.length) {\n            sb.append(\"UNKNOWN_TAG\");\n        } else {\n            sb.append(CTRL_MSG_TAGS[tag]);\n        }\n        sb.append(\" msg: \").append(message);\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTKeyAttachement.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.HeaderBufferPool;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Abstract class implemented by both the reader and writer keys TODO - Use finer grained synchronization mechanism\n * instead of syncronized on the entire key\n *\n * @author ramiro\n */\npublic abstract class FDTKeyAttachement {\n\n    private static final AtomicInteger SEQ = new AtomicInteger(0);\n\n    private static final HeaderBufferPool headerPool = HeaderBufferPool.getInstance();\n\n    private static final DirectByteBufferPool payloadPool = DirectByteBufferPool.getInstance();\n\n    /*\n     * int - version 32 bits ( 4 bytes ) int - headerSize 32 bits ( 4 bytes ) int - buffer size 32 bits ( 4 bytes ) long\n     * - timeStamp 64 bits ( 8 bytes ) long - seq 64 bits ( 8 bytes ) int - packet type 32 bits ( 4 bytes ) UUID - 2\n     * long-s 128 bits ( 16 bytes ) long - offset in file 64 bits ( 8 bytes )\n     */\n    protected final int seq;\n    private final ByteBuffer[] _array = new ByteBuffer[2];\n    public FDTSelectionKey fdtSelectionKey;\n    protected boolean useFixedSizeBlocks;\n    private ByteBuffer header;\n    private ByteBuffer payload;\n\n    public FDTKeyAttachement(FDTSelectionKey fdtSelectionKey, boolean useFixedSizeBlocks) {\n        this.header = null;\n        this.payload = null;\n        this.seq = SEQ.getAndIncrement();\n        this.fdtSelectionKey = fdtSelectionKey;\n        this.useFixedSizeBlocks = useFixedSizeBlocks;\n    }\n\n    /**\n     * This MUST stay synchronized\n     *\n     * @param header\n     * @param payload\n     */\n    public synchronized void setBuffers(ByteBuffer header, ByteBuffer payload) {\n        this.header = header;\n        this.payload = payload;\n        setArray();\n    }\n\n    /**\n     * will always be called from synchronized block\n     */\n    private void setArray() {\n        this._array[0] = this.header;\n        this._array[1] = this.payload;\n    }\n\n    /**\n     * This MUST stay synchronized\n     */\n    public synchronized void recycleBuffers() {\n        if (this.header != null) {\n            headerPool.put(this.header);\n            this.header = null;\n        }\n\n        if (this.payload != null) {\n            payloadPool.put(this.payload);\n            this.payload = null;\n        }\n\n        setArray();\n    }\n\n    public synchronized void recycleAndSetPayload(ByteBuffer bb) {\n        if (this.payload != null) {\n            payloadPool.put(this.payload);\n        }\n        this.payload = bb;\n        setArray();\n    }\n\n    public synchronized void setPayload(ByteBuffer bb) {\n        this.payload = bb;\n        setArray();\n    }\n\n    public synchronized void recycleHeader() {\n        if (this.header != null) {\n            headerPool.put(this.header);\n            this.header = null;\n        }\n        setArray();\n    }\n\n    public synchronized void recyclePaylod() {\n        if (this.payload != null) {\n            payloadPool.put(this.payload);\n            this.payload = null;\n        }\n        setArray();\n    }\n\n    public synchronized boolean recycleAndSetBuffers() throws InterruptedException {\n\n        recycleBuffers();\n\n        ByteBuffer _header = null;\n        ByteBuffer _payload = null;\n\n        try {\n            _header = headerPool.poll(2, TimeUnit.SECONDS);\n            if (_header != null) {\n                _payload = payloadPool.poll(2, TimeUnit.SECONDS);\n            }\n        } finally {\n            if (_header == null) {\n                return false;\n            }\n\n            if (_payload == null) {\n                // do not loose header buffers if payload buffers not available\n                if (_header != null) {\n                    headerPool.put(_header);\n                    header = null;\n                }\n                return false;\n            }\n        }\n\n        setBuffers(_header, _payload);\n\n        return true;\n    }\n\n    public synchronized boolean hasBuffers() {\n        return ((header != null) && (payload != null));\n    }\n\n    public synchronized boolean hasHeader() {\n        return (header != null);\n    }\n\n    public synchronized boolean hasPayload() {\n        return (payload != null);\n    }\n\n    public synchronized ByteBuffer[] asArray() {\n        return _array;\n    }\n\n    public final boolean useFixedSizeBlocks() {\n        return useFixedSizeBlocks;\n    }\n\n    public synchronized final ByteBuffer header() {\n        return header;\n    }\n\n    public synchronized final ByteBuffer payload() {\n        return payload;\n    }\n\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"SocketAttachement :- header: \").append(header).append(\" :- payload: \").append(payload);\n        return sb.toString();\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTListFilesMsg.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * The list files msg between FDT peers.\n *\n * @author Raimondas Sirvinskas\n */\npublic class FDTListFilesMsg implements Serializable {\n\n    public String listFilesFrom;\n    public List<String> filesInDir;\n\n    public FDTListFilesMsg(String listFilesFrom) {\n        this.listFilesFrom = listFilesFrom;\n        this.filesInDir = new ArrayList<>();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"\\n listFilesFrom: \").append(listFilesFrom);\n        sb.append(\"\\n filesInDir: \").append(filesInDir.toString());\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTProcolException.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\n/**\n * Exception used to signal protcol exception at the FDT Application level\n * Usually this kind of Exception happen if there is a BUG inside FDT protocol\n * or someone is trying to hijack the established FDT Session\n *\n * @author ramiro\n */\npublic class FDTProcolException extends Exception {\n\n    private static final long serialVersionUID = 4606073777542177510L;\n\n    public FDTProcolException() {\n        super();\n    }\n\n    public FDTProcolException(String message) {\n        super(message);\n    }\n\n    public FDTProcolException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public FDTProcolException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTReaderKeyAttachement.java",
    "content": "/*\n * $Id$\n */\n\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.nio.ByteBuffer;\nimport java.util.UUID;\n\n/**\n * The key selection used by the \"read\" sockets TODO - Use finer grained synchronization mechanism instead of\n * syncronized on the entire key\n *\n * @author ramiro\n */\nclass FDTReaderKeyAttachement extends FDTKeyAttachement {\n\n    public int version;\n\n    public int packetType;\n\n    public UUID uuid;\n\n    public long fileOffset;\n\n    // payload size()\n    public volatile int payloadSize;\n\n    public volatile long seq;\n\n    public volatile long tstamp;\n\n    // cache the header processing\n    boolean isHeaderProcessed;\n\n    FDTReaderKeyAttachement(FDTSelectionKey fdtSelectionKey, boolean useFixedSizeBlocks) {\n        super(fdtSelectionKey, useFixedSizeBlocks);\n        isHeaderProcessed = false;\n    }\n\n    public synchronized final FileBlock toFileBlock() {\n        final ByteBuffer payload = payload();\n        payload.flip();\n        payload.limit(payloadSize);\n        FileBlock fileBlock = FileBlock.getInstance(fdtSelectionKey.fdtSessionID(), uuid, fileOffset, payload);\n        setPayload(null);\n        return fileBlock;\n    }\n\n    public synchronized boolean isHeaderRead() {\n        if (isHeaderProcessed) {\n            return true;\n        }\n\n        final ByteBuffer header = header();\n        if (header != null && !header.hasRemaining()) {\n            processHeader();\n            isHeaderProcessed = true;\n            return true;\n        }\n        return false;\n    }\n\n    private void processHeader() {\n\n        final ByteBuffer header = header();\n\n        header.flip();\n\n        // read the version\n        version = header.getInt();\n\n        // packet type\n        packetType = header.getInt();\n\n        // header size\n        header.getInt();\n\n        // payload size\n        payloadSize = header.getInt();\n\n        // the packet tag\n        seq = header.getLong();\n\n        // timeStamp\n        tstamp = header.getLong();\n\n        // read the uuid\n        uuid = new UUID(header.getLong(), header.getLong());\n\n        fileOffset = header.getLong();\n\n        if (!useFixedSizeBlocks) {\n            payload().limit(payloadSize);\n        }\n    }\n\n    public synchronized void setBuffers(ByteBuffer header, ByteBuffer payload) {\n        super.setBuffers(header, payload);\n        isHeaderProcessed = false;\n    }\n\n    public synchronized boolean isPayloadRead() {\n        final ByteBuffer payload = payload();\n        return (payload != null && !payload.hasRemaining());\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTSessionConfigMsg.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\n\nimport java.io.Serializable;\nimport java.util.Arrays;\nimport java.util.UUID;\n\n/**\n * The config msg between FDT peers.\n *\n * @author ramiro\n */\npublic class FDTSessionConfigMsg implements Serializable {\n\n    private static final long serialVersionUID = 691756564099111644L;\n\n\n    public String destinationDir;\n    public String destinationIP;\n    public int destinationPort;\n    public boolean recursive;\n\n    //future? use\n    public String dirOffset;\n\n    public String sourceIP;\n\n    public UUID[] fileIDs;\n    public String[] fileLists;\n    public String[] remappedFileLists;\n    public long[] fileSizes;\n    public long[] lastModifTimes;\n\n    public FDTSessionConfigMsg() {\n\n    }\n\n    public FDTSessionConfigMsg(Config config) {\n        this.destinationIP = config.getDestinationIP();\n        this.destinationDir = config.getDestinationDir();\n        this.sourceIP = config.getSourceIP();\n        this.fileLists = config.getFileList();\n        this.destinationPort = config.getDestinationPort();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"\\n destinationDir: \").append(destinationDir);\n        sb.append(\"\\n destinationIP: \").append(destinationIP != null ? destinationIP : \"\");\n        sb.append(\"\\n destinationPort: \").append(String.valueOf(destinationPort));\n        sb.append(\"\\n sourceIP: \").append(sourceIP != null ? sourceIP : \"\");\n        sb.append(\" recursive: \").append(recursive);\n        sb.append(\" dirOffset: \").append(dirOffset);\n        sb.append(\"\\n UUID[]: \").append(Arrays.toString(fileIDs));\n        sb.append(\"\\n fileList[]: \").append(Arrays.toString(fileLists));\n        sb.append(\"\\n remappedFileLists[]: \").append(Arrays.toString(remappedFileLists));\n        sb.append(\"\\n fileSizes[]: \").append(Arrays.toString(fileSizes));\n        sb.append(\"\\n lastModifTimes[]: \").append(Arrays.toString(lastModifTimes));\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTWriterKeyAttachement.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.HeaderBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\n\n\n/**\n * Specific FDT attachement for a channel performing write.\n *\n * @author ramiro\n */\nclass FDTWriterKeyAttachement extends FDTKeyAttachement implements Comparable<FDTWriterKeyAttachement> {\n\n    private static final HeaderBufferPool hbp = Utils.getHeaderBufferPool();\n    private static AtomicLong SEQ = new AtomicLong(0L);\n    final AtomicLong lastOperation = new AtomicLong(0L);\n    final AtomicBoolean connectCookieSent;\n    volatile int payloadSize;\n    FileBlock fileBlock;\n\n    public FDTWriterKeyAttachement(FDTSelectionKey fdtSelectionKey, boolean useFixedSizeBlocks, boolean connectCookieSent) {\n        super(fdtSelectionKey, useFixedSizeBlocks);\n        this.connectCookieSent = new AtomicBoolean(connectCookieSent);\n    }\n\n    public static final boolean fromFileBlock(FileBlock fileBlock, FDTWriterKeyAttachement wsa) throws InterruptedException {\n        if (fileBlock == null) return false;\n\n        wsa.recycleBuffers();\n\n        ByteBuffer header = hbp.take();\n\n        if (header == null) return false;\n\n        long seq = SEQ.getAndIncrement();\n\n        //the version\n        //TODO - make it parameter\n        header.putInt(2);\n\n        //the packet type\n        header.putInt(1);\n\n        //Header Size\n        header.putInt(Config.HEADER_SIZE);\n\n        //payload size()\n        header.putInt(fileBlock.buff.limit());\n\n        //the tstamp - future use for MUX streams?\n        header.putLong(0L);\n\n        //packet SEQ - future use for MUX streams\n        header.putLong(seq);\n\n\n        //the UUID\n        header.putLong(fileBlock.fileSessionID.getMostSignificantBits()).putLong(fileBlock.fileSessionID.getLeastSignificantBits());\n\n        //the offset\n        header.putLong(fileBlock.fileOffset);\n\n\n        //make it ready :)\n        header.flip();\n\n        //if used fixed size ... than increase the limit to the buffer capacity\n        if (wsa.useFixedSizeBlocks) {\n            fileBlock.buff.limit(fileBlock.buff.capacity());\n        }\n        wsa.setBuffers(header, fileBlock.buff);\n        wsa.payloadSize = fileBlock.buff.limit();\n\n        //keep the reference to the FileBlock to recycle it\n        wsa.setBuffers(header, fileBlock.buff);\n\n        return true;\n    }\n\n    public synchronized boolean isHeaderWritten() {\n        return !header().hasRemaining();\n    }\n\n    public synchronized boolean isPayloadWritten() {\n        return !(payload().position() < payloadSize);\n    }\n\n    public final void updateLastOperation() {\n        this.lastOperation.set(System.nanoTime());\n    }\n\n    public int compareTo(FDTWriterKeyAttachement o) {\n\n        if (this == o) return 0;\n\n        final long diff = this.lastOperation.get() - o.lastOperation.get();\n\n        if (diff < 0L) return -1;\n        if (diff > 0L) return 1;\n\n        //should return 0; check the seq anyway\n        if (this.seq < o.seq) return -1;\n\n        return 1;\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/FDTWriterKeyAttachementComparator.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.io.Serializable;\nimport java.util.Comparator;\n\n/**\n * @author ramiro\n */\npublic class FDTWriterKeyAttachementComparator implements Comparator<FDTSelectionKey>, Serializable {\n\n    /**\n     * findbugs suggested i should make the comparator .... Serializable\n     */\n    private static final long serialVersionUID = -9190255291921632210L;\n\n    public int compare(final FDTSelectionKey sk1, final FDTSelectionKey sk2) {\n\n        if (sk1 == sk2) return 0;\n\n        final FDTWriterKeyAttachement sk1Attach = (FDTWriterKeyAttachement) sk1.attachment();\n        final FDTWriterKeyAttachement sk2Attach = (FDTWriterKeyAttachement) sk2.attachment();\n\n        return sk1Attach.compareTo(sk2Attach);\n    }\n\n}"
  },
  {
    "path": "src/lia/util/net/copy/transport/PingDaemon.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Utils;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Should provide RTT between peers\n *\n * @author ramiro\n */\npublic class PingDaemon {\n\n    private static final Logger logger = Logger.getLogger(\"lia.util.net.copy.transport.PingDaemon\");\n    private static final int DEFAULT_CONNECT_DELAY = 20;\n    private static final int DEFAULT_PING_DELAY = 20;\n    private static final TimeUnit DEFAULT_PING_DELAY_TIME_UNIT = TimeUnit.SECONDS;\n    private static final int DEFAULT_PACKET_SIZE = 1500;//bytes\n    private static final int FDT_PING = 1;\n    private static final int FDT_PING_REPLY = 2;\n    private long pingDelay;\n    private TimeUnit pingDelayTimeUnit;\n    private SocketChannel sc;\n    private int packetSize;\n    private ByteBuffer header;\n    private ByteBuffer payload;\n    private long SEQ = 0;\n    private ByteBuffer[] toSend = new ByteBuffer[2];\n\n    public PingDaemon(SocketChannel sc) throws Exception {\n\n        sc.configureBlocking(true);\n        this.sc = sc;\n        initChannels();\n\n        new PingServer().start();\n    }\n\n    public PingDaemon(InetAddress inetAddr, int port) throws Exception {\n        this(inetAddr, port, DEFAULT_CONNECT_DELAY, DEFAULT_PING_DELAY, DEFAULT_PING_DELAY_TIME_UNIT, DEFAULT_PACKET_SIZE);\n    }\n\n    public PingDaemon(InetAddress inetAddr, int port, long pingDelay,\n                      TimeUnit pingDelayTimeUnit, int packetSize) throws Exception {\n        this(inetAddr, port, DEFAULT_CONNECT_DELAY, pingDelay, pingDelayTimeUnit, packetSize);\n    }\n\n    public PingDaemon(InetAddress inetAddr, int port, int connectDelay, long pingDelay,\n                      TimeUnit pingDelayTimeUnit, int packetSize) throws Exception {\n\n        this.packetSize = packetSize;\n        this.pingDelay = pingDelay;\n        this.pingDelayTimeUnit = pingDelayTimeUnit;\n\n        sc = SocketChannel.open();\n        sc.configureBlocking(true);\n\n        sc.socket().connect(new InetSocketAddress(inetAddr, port), 30 * 1000);\n\n        initChannels();\n\n        payload = ByteBuffer.allocateDirect(DEFAULT_PACKET_SIZE - header.capacity());\n\n        header.putInt(FDT_PING);\n        header.putInt(1);\n        header.putInt(payload.capacity());\n\n        toSend[0] = header;\n        toSend[1] = payload;\n\n        Utils.getMonitoringExecService().scheduleWithFixedDelay(new PingerTask(), 5, 20, TimeUnit.SECONDS);\n\n    }\n\n    public static final void main(String[] args) throws Exception {\n\n        try {\n            //Start in server mode\n            if (args == null || args.length == 0) {\n            } else if (args.length == 1) {\n                final int port = Integer.parseInt(args[0]);\n                ServerSocketChannel ssc = ServerSocketChannel.open();\n                ssc.configureBlocking(true);\n                ssc.socket().bind(new InetSocketAddress(port));\n\n                try {\n                    SocketChannel sc = ssc.accept();\n                    new PingDaemon(sc);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            } else if (args.length == 2) {\n                InetAddress ia = InetAddress.getByName(args[0]);\n                final int port = Integer.parseInt(args[1]);\n                new PingDaemon(ia, port);\n            }\n        } catch (Throwable t) {\n            t.printStackTrace();\n            System.exit(1);\n        }\n\n\n        for (; ; ) {\n            try {\n                Thread.sleep(100000);\n            } catch (Throwable t1) {\n            }\n        }\n    }\n\n    private void initChannels() throws Exception {\n\n        header = ByteBuffer.allocateDirect(20);\n\n    }\n\n    public void setDelay(long pingDelay, TimeUnit pingDelayTimeUnit) {\n        this.pingDelay = pingDelay;\n        this.pingDelayTimeUnit = pingDelayTimeUnit;\n    }\n\n    public void setPacketSize(int packetSize) {\n        this.packetSize = packetSize;\n    }\n\n    private final class PingServer extends Thread {\n\n        public PingServer() {\n            super(\" (FDT) Ping Daemon\");\n            this.setDaemon(true);\n        }\n\n        public void run() {\n\n            for (; ; ) {\n                try {\n\n                    if (!sc.isOpen() || sc.socket().isClosed()) {\n                        break;\n                    }\n\n                    header.clear();\n                    if (sc.read(header) == -1) {\n                        break;\n                    }\n\n                    header.flip();\n\n                    final int type = header.getInt();\n                    final int version = header.getInt();\n                    final int payloadSize = header.getInt();\n                    final long seq = header.getLong();\n\n                    System.out.println(\"Read from client: [ SEQ: \" + seq + \" type: \" + type + \" version: \" + version + \" payloadSize: \" + payloadSize + \" ]\");\n\n                    if (payload == null || payload.capacity() != payloadSize) {\n                        payload = ByteBuffer.allocateDirect(payloadSize);\n                        toSend[0] = header;\n                        toSend[1] = payload;\n                    }\n\n                    payload.clear();\n                    sc.read(payload);\n\n                    header.flip();\n                    header.putInt(FDT_PING_REPLY);\n\n                    header.position(header.capacity());\n                    payload.position(payload.capacity());\n\n                    header.flip();\n                    payload.flip();\n\n                    sc.write(toSend);\n\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Got exception \", t);\n                }\n            }//end for\n\n            System.out.println(\"Server exits!\");\n        }\n    }\n\n    private final class PingerTask implements Runnable {\n\n        public void run() {\n            try {\n\n                header.position(12);\n                header.putLong(SEQ++);\n                header.position(header.capacity());\n\n                payload.position(payload.capacity());\n                header.flip();\n                payload.flip();\n\n                final long sTime = System.nanoTime();\n                System.out.println(\" Written: \" + sc.write(toSend));\n\n                header.clear();\n                payload.clear();\n\n                sc.read(toSend);\n                final long finishTime = System.nanoTime();\n\n                System.out.println(\" DT = \" + (finishTime - sTime) / (1000D * 1000D) + \" ms\");\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \"Got exception\", t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/SocketReaderTask.java",
    "content": "/*\n * $Id$\n */\n\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.FileBlockConsumer;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The one and (not the) only reader task for a channel\n *\n * @author ramiro\n */\npublic class SocketReaderTask extends SocketTask {\n\n    private static final Logger logger = Logger.getLogger(SocketReaderTask.class.getName());\n\n    private static final int RETRY_IO_COUNT = Config.getInstance().getRetryIOCount();\n\n    final AtomicReference<FDTSelectionKey> fdtSelectionKeyRef = new AtomicReference<FDTSelectionKey>();\n\n    private final TCPSessionReader master;\n\n    private final FileBlockConsumer fileBlockConsumer;\n\n    private final boolean isNetTest;\n\n    SocketReaderTask(BlockingQueue<FDTSelectionKey> readyChannelsQueue, FileBlockConsumer fileBlockConsumer, TCPSessionReader master) {\n        super(readyChannelsQueue);\n        this.fileBlockConsumer = fileBlockConsumer;\n        this.master = master;\n        isNetTest = master.isNetTest();\n    }\n\n    private boolean setAttachementBuffers(FDTReaderKeyAttachement attach) throws InterruptedException {\n        return attach.recycleAndSetBuffers();\n    }\n\n    private final boolean checkForData() throws InterruptedException {\n        final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.get();\n        final FDTReaderKeyAttachement attach = (FDTReaderKeyAttachement) fdtSelectionKey.attachment();\n\n        if (attach.isHeaderRead() && attach.isPayloadRead()) {// everything has been read\n            fdtSelectionKey.opCount = 0;\n\n            addAndGetUtilBytes(attach.payloadSize);\n            master.addAndGetUtilBytes(attach.payloadSize);\n\n            if (isNetTest) {\n                attach.header().clear();\n                return false;\n            }\n\n            if (!master.localLoop()) {\n                final FileBlock fileBlock = attach.toFileBlock();\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"<SocketReaderTask> read a full FileBlock for: \" + Utils.buffToString(fileBlock.buff));\n                }\n\n                boolean offered = false;\n                try {\n                    for (; ; ) {\n                        offered = fileBlockConsumer.offer(fileBlock, 5, TimeUnit.SECONDS);\n                        if (offered)\n                            break;\n                        if (isClosed() || Thread.currentThread().isInterrupted())\n                            break;\n                    }\n                } finally {\n                    if (!offered) {\n                        if (!offered && fileBlock != null && fileBlock.buff != null) {\n                            DirectByteBufferPool.getInstance().put(fileBlock.buff);\n                        }\n                        recycleBuffers();\n                        return false;\n                    }\n                }\n            } else {\n                attach.recyclePaylod();\n            }\n\n            attach.recycleHeader();\n            return true;\n        }\n\n        return false;\n    }\n\n    private boolean readData() throws Exception {\n\n        final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.get();\n        final FDTReaderKeyAttachement attach = (FDTReaderKeyAttachement) fdtSelectionKey.attachment();\n        final SocketChannel sc = fdtSelectionKey.channel();\n\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        if (logFinest) {\n            logger.log(Level.FINEST, \" [ SocketReaderTask ] [ readData ] for \" + Utils.toStringSelectionKey(fdtSelectionKey));\n        }\n\n        long count = -1;\n\n        if (!attach.hasBuffers()) {\n            if (!attach.recycleAndSetBuffers()) {\n                return false;\n            }\n        } else {\n            if (checkForData()) {\n                if (!setAttachementBuffers(attach)) {\n                    return false;\n                }\n                if (isClosed()) {\n                    attach.recycleBuffers();\n                }\n            }\n        }\n\n        final ByteBuffer bpl = attach.payload();\n        for (; ; ) {\n            if (isClosed() || Thread.currentThread().isInterrupted())\n                break;\n\n            if (isNetTest) {\n                attach.isHeaderProcessed = true;\n                bpl.clear();\n                // attach.header.clear();\n                count = sc.read(bpl);\n                if (isBlocking) {\n                    while (count >= 0) {\n                        addAndGetTotalBytes(count);\n                        master.addAndGetTotalBytes(count);\n                        bpl.clear();\n                        count = sc.read(bpl);\n                        continue;\n                    }\n                }\n            } else if (attach.useFixedSizeBlocks) {\n                count = sc.read(attach.asArray());\n            } else {// parse the header first\n                if (attach.isHeaderRead()) {\n                    count = sc.read(attach.payload());\n                } else {\n                    count = sc.read(attach.header());\n                    if (attach.isHeaderRead()) {\n                        addAndGetTotalBytes(count);\n                        if (logFinest) {\n                            logger.log(Level.FINEST, \" [ SocketReaderTask ] socket: \" + sc.socket() + \" count: \" + count);\n                        }\n                        master.addAndGetTotalBytes(count);\n                        count = sc.read(attach.payload());\n                    }\n                }\n            }\n\n            if (count > 0) {\n\n                fdtSelectionKey.opCount = 0;\n\n                if (logFinest) {\n                    logger.log(Level.FINEST, \" [ SocketReaderTask ] socket: \" + sc.socket() + \" count: \" + count);\n                }\n\n                addAndGetTotalBytes(count);\n                master.addAndGetTotalBytes(count);\n\n                if (checkForData()) {\n                    if (!setAttachementBuffers(attach)) {\n                        return false;\n                    }\n                    if (isClosed()) {\n                        attach.recycleBuffers();\n                    }\n                }\n\n                continue;\n            } else if (count == 0) {\n\n                if (checkForData()) {\n                    if (setAttachementBuffers(attach)) {\n                        if (isClosed()) {\n                            attach.recycleBuffers();\n                        }\n                        continue;\n                    }\n                }\n\n                // try multiple IO Reads ...\n                if (fdtSelectionKey.opCount++ > RETRY_IO_COUNT) {\n                    if (isBlocking) {\n                        if (!attach.hasBuffers()) {\n                            break;\n                        }\n\n                        logger.log(Level.WARNING, \" reached RETRY_IO_COUNT in blocking mode ... remote peer down?! SC is blocking: \" + sc.isBlocking());\n                        master.workerDown(fdtSelectionKey, null);\n                    }\n\n                    if (attach.hasBuffers()) {\n                        fdtSelectionKey.renewInterest();\n                        return true;\n                    }\n\n                    break;\n                }\n\n                continue;\n            } else {\n                master.workerDown(fdtSelectionKey, null);\n                close(\"EOF\", null);\n            }\n\n        }\n\n        return false;\n    }\n\n    private void recycleBuffers() {\n        try {\n            final FDTSelectionKey fdtSelectionKey = this.fdtSelectionKeyRef.get();\n            if (fdtSelectionKey != null) {\n                FDTKeyAttachement attach = fdtSelectionKey.attachment();\n                if (attach != null) {\n                    attach.recycleBuffers();\n                }\n            }\n        } catch (Throwable t1) {\n            logger.log(Level.WARNING, \" Got exception trying to recover the buffers and returning them to pool\", t1);\n        }\n    }\n\n    public void internalClose() {\n        final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.getAndSet(null);\n        if (fdtSelectionKey != null) {\n            fdtSelectionKey.cancel();\n\n            final SocketChannel sc = fdtSelectionKey.channel();\n            if (sc != null) {\n                try {\n                    sc.close();\n                } catch (Throwable t) {\n                }\n            }\n\n            final FDTKeyAttachement keyAttachement = fdtSelectionKey.attachment();\n            if (keyAttachement != null) {\n                try {\n                    keyAttachement.recycleBuffers();\n                } catch (Throwable t) {\n                }\n            }\n        }\n    }\n\n    public void run() {\n        String cName = Thread.currentThread().getName();\n        String name = \" SocketReaderTask for [ \" + master.fdtSession.sessionID() + \" ]\";\n        Thread.currentThread().setName(name);\n\n        if (logger.isLoggable(Level.FINE)) {\n            logger.log(Level.FINE, name + \" STARTED !\");\n        }\n\n        try {\n            for (; ; ) {\n                // use a local FDTSelKey for a little speed-up\n                FDTSelectionKey iSel = null;\n                fdtSelectionKeyRef.set(null);\n                try {\n                    while (iSel == null) {\n                        fdtSelectionKeyRef.getAndSet(readyChannelsQueue.poll(2, TimeUnit.SECONDS));\n                        iSel = fdtSelectionKeyRef.get();\n                        if (isClosed()) {\n                            break;\n                        }\n                    }\n                } catch (InterruptedException ie) {\n                    if (!isClosed()) {\n                        logger.log(Level.INFO, name + \" was interrupted ... \", ie);\n                    } else {\n                        break;\n                    }\n                    Thread.interrupted();\n                    close(\"Got interrupted exception\", ie);\n                }\n\n                final FDTSelectionKey fdtSelectionKey = iSel;\n                if (isClosed() || fdtSelectionKey == null)\n                    break;\n\n                try {\n                    if (!readData()) {\n                        if (!isClosed()) {\n                            if (readyChannelsQueue.offer(fdtSelectionKeyRef.getAndSet(null))) {\n                                throw new FDTProcolException(\" Unable to add selection key in the selection queue\");\n                            }\n                        } else {\n                            recycleBuffers();\n                        }\n                    }\n                } catch (Throwable t) {\n                    master.close(\"Exception reading data\", t);\n\n                    recycleBuffers();\n\n                    close(\" Got exception trying to readData() from channel\", t);\n                    break;\n                }\n            } // for(;;)\n\n        } finally {\n            try {\n                final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.get();\n\n                if (fdtSelectionKey != null) {\n                    final FDTKeyAttachement attach = fdtSelectionKey.attachment();\n                    if (attach != null) {\n                        attach.recycleBuffers();\n                    }\n                }\n            } catch (Throwable t1) {\n                logger.log(Level.WARNING, \" Got exception trying to return buffers to the pool\", t1);\n            }\n\n            Thread.currentThread().setName(cName);\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.INFO, name + \" FINISHED !\");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/SocketTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.AbstractFDTIOEntity;\nimport lia.util.net.common.Config;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.util.concurrent.BlockingQueue;\n\n/**\n * The base class for to fill/drain a socket channel.\n *\n * @author ramiro\n */\npublic abstract class SocketTask extends AbstractFDTIOEntity implements Runnable {\n    protected static final boolean isBlocking = Config.getInstance().isBlocking();\n\n    protected final BlockingQueue<FDTSelectionKey> readyChannelsQueue;\n\n    public SocketTask(BlockingQueue<FDTSelectionKey> readyChannelsQueue) {\n        this.readyChannelsQueue = readyChannelsQueue;\n    }\n\n    public long getSize() {\n        return -1;\n    }\n\n    protected void internalClose() throws Exception {\n        try {\n            for (final FDTSelectionKey selKey : readyChannelsQueue) {\n                final FDTKeyAttachement attach = selKey.attachment();\n                if (attach != null) {\n                    attach.recycleBuffers();\n                }\n            }\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/SocketWriterTask.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.HeaderBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FileBlock;\nimport lia.util.net.copy.FileBlockProducer;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The one and (not the) only writer over a channel\n *\n * @author ramiro\n */\npublic class SocketWriterTask extends SocketTask {\n\n    /**\n     * Logger used by this class\n     */\n    private static final Logger logger = Logger.getLogger(SocketWriterTask.class.getName());\n    // private static final int MSS_SIZE = 16 * 1024 * 1024;\n    private static final int BUFF_LEN_SIZE = Config.NETWORK_BUFF_LEN_SIZE;\n    private final AtomicReference<FDTSelectionKey> fdtSelectionKeyRef = new AtomicReference<FDTSelectionKey>(null);\n\n    // private static final int BUFF_LEN_SIZE = 16 * 1024 * 1024;\n\n    // private static final int RETRY_IO_COUNT = Config.getInstance().getRetryIOCount();\n    private final TCPSessionWriter master;\n\n    private final FileBlockProducer fileBlockProducer;\n\n    private final boolean isNetTest;\n\n    SocketWriterTask(BlockingQueue<FDTSelectionKey> readyChannelsQueue, FileBlockProducer fileBlockProducer, TCPSessionWriter master) {\n        super(readyChannelsQueue);\n        this.fileBlockProducer = fileBlockProducer;\n        this.master = master;\n        this.isNetTest = master.isNetTest();\n    }\n\n    private long writeToChannel(SocketChannel sc, ByteBuffer[] buffsToWrite) throws IOException {\n        final ByteBuffer[] bToWrite = buffsToWrite;\n        if (isNetTest) {\n            for (final ByteBuffer b : bToWrite) {\n                b.position(0);\n                b.limit(b.capacity());\n            }\n        }\n\n        return sc.write(bToWrite);\n    }\n\n    private long writeData() throws IOException, InterruptedException {\n        final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.get();\n        final FDTWriterKeyAttachement attach = (FDTWriterKeyAttachement) fdtSelectionKey.attachment();\n        final boolean connectCookieSent = attach.connectCookieSent.get();\n\n        long count = -1;\n        final SocketChannel sc = fdtSelectionKey.channel();\n\n        int mss = fdtSelectionKey.getMSS();\n        int bufferSize = BUFF_LEN_SIZE;\n        mss = -1;\n        if (mss > 0) {\n            bufferSize = mss;\n        }\n\n        final boolean logFinest = logger.isLoggable(Level.FINEST);\n        if (logFinest) {\n            logger.log(Level.FINEST, \"Using MSS: \" + bufferSize + \" for socket channel: \" + sc);\n        }\n\n        final DirectByteBufferPool dbPool = DirectByteBufferPool.getInstance();\n        final HeaderBufferPool hbPool = HeaderBufferPool.getInstance();\n\n        for (; ; ) {\n            count = -1;\n            if (!attach.hasBuffers()) {\n                if (isNetTest) {\n\n                    ByteBuffer bb = null;\n                    ByteBuffer hh = null;\n\n                    try {\n                        bb = dbPool.take();\n                        hh = hbPool.take();\n                    } finally {\n                        if (isClosed() || Thread.currentThread().isInterrupted()) {\n                            if (bb != null) {\n                                dbPool.put(bb);\n                            }\n\n                            if (hh != null) {\n                                hbPool.put(hh);\n                            }\n                            return count;\n                        }\n                    }\n\n                    if (hh == null || bb == null) {\n                        // not enough buffer space - return what we coudl not get\n                        if (bb != null) {\n                            dbPool.put(bb);\n                        }\n\n                        if (hh != null) {\n                            hbPool.put(hh);\n                        }\n\n                        // BUG FIXED!! ... It is possible to have only one SelectionKey in the Queue ... at the end of\n                        // an session\n                        attach.updateLastOperation();\n\n                        // END BUG FIXED!!\n\n                        readyChannelsQueue.offer(fdtSelectionKey);\n                        if (logFinest) {\n                            logger.log(Level.FINEST, \" [ SocketWriterTask ] Empty FD queue. Added SK: \" + fdtSelectionKey + \" NEW Sel Queue: \" + readyChannelsQueue);\n                        }\n                        return 0;\n                    }\n\n                    bb.position(0);\n                    bb.limit(bb.capacity());\n                    hh.position(0);\n                    hh.limit(hh.capacity());\n                    attach.setBuffers(hh, bb);\n\n                } else {\n                    FileBlock fb = fileBlockProducer.poll(5, TimeUnit.SECONDS);\n\n                    if (fb == null) {\n                        // not enough buffer space\n\n                        // BUG FIXED!! ... It is possible to have only one SelectionKey in the Queue ... at the end of\n                        // an session\n                        attach.updateLastOperation();\n\n                        // END BUG FIXED!!\n\n                        readyChannelsQueue.offer(fdtSelectionKey);\n                        if (logFinest) {\n                            logger.log(Level.FINEST, \" [ SocketWriterTask ] Empty FD queue. Added SK: \" + fdtSelectionKey + \" NEW Sel Queue: \" + readyChannelsQueue);\n                        }\n                        return 0;\n                    }\n\n                    boolean bRet = false;\n                    try {\n                        bRet = FDTWriterKeyAttachement.fromFileBlock(fb, attach);\n                    } finally {\n                        if (!bRet) {\n                            attach.recycleBuffers();\n                            if (fb != null && fb.buff != null) {\n                                dbPool.put(fb.buff);\n                                fb = null;\n                            }\n                        }\n                    }\n\n                }\n\n            }// if no buffers attached\n\n            count = -1;\n            final int cPos = attach.payload().position();\n            long canWrite = (attach.payloadSize - cPos);\n\n            if (canWrite > bufferSize) {\n                canWrite = bufferSize;\n            }\n\n            if (master.getRateLimit() > 0) {\n                final long shouldWrite = master.awaitSend(canWrite);\n                if (shouldWrite < canWrite) {\n                    canWrite = shouldWrite;\n                }\n\n                attach.payload().limit(cPos + (int) canWrite);\n            }\n\n            if (!connectCookieSent) {\n\n                ByteBuffer connectCookie = null;\n                try {\n                    connectCookie = dbPool.take();\n                    if (!isNetTest) {\n                        connectCookie.limit(1 + 16);\n                    } else {\n                        connectCookie.limit(connectCookie.capacity());\n                    }\n\n                    connectCookie.put((byte) 1).putLong(master.fdtSession.sessionID().getMostSignificantBits()).putLong(master.fdtSession.sessionID().getLeastSignificantBits());\n                    if (isNetTest) {\n                        connectCookie.position(connectCookie.capacity());\n                    }\n                    connectCookie.flip();\n\n                    long tmpW = 0;\n                    while (connectCookie.hasRemaining()) {\n                        count = sc.write(connectCookie);\n                        tmpW += count;\n                        if (isNetTest && tmpW >= 18) {\n                            break;\n                        }\n                    }\n\n                    attach.connectCookieSent.set(true);\n                } finally {\n                    if (connectCookie != null) {\n                        dbPool.put(connectCookie);\n                        if (!attach.connectCookieSent.get()) {\n                            close(\"Unable to send connect cookie\", new IOException(\"Unable to send connect cookie\"));\n                        }\n                    }\n                }\n            }\n\n            while ((count = writeToChannel(sc, attach.asArray())) > 0) {\n                if (isNetTest) {\n                    fdtSelectionKey.opCount = 0;\n                    addAndGetTotalBytes(count);\n                    master.addAndGetTotalBytes(count);\n                    continue;\n                }\n\n                attach.payload().limit(attach.payloadSize);\n\n                fdtSelectionKey.opCount = 0;\n                addAndGetTotalBytes(count);\n                master.addAndGetTotalBytes(count);\n\n                if (logFinest) {\n                    logger.log(Level.FINEST, \" [ SocketWriterTask ] Socket: \" + sc.socket() + \" written: \" + count);\n                }\n\n                attach.updateLastOperation();\n                // TODO - add accounting\n                if (attach.isPayloadWritten()) {\n\n                    final long ladd = attach.payload().limit();\n                    addAndGetUtilBytes(ladd);\n                    master.addAndGetUtilBytes(ladd);\n\n                    if (isNetTest) {\n\n                        final ByteBuffer h = attach.header();\n                        h.position(0);\n                        h.limit(h.capacity());\n\n                        final ByteBuffer p = attach.payload();\n                        p.position(0);\n                        p.limit(p.capacity());\n\n                    } else {\n\n                        attach.recycleBuffers();\n\n                        FileBlock fb = fileBlockProducer.poll(5, TimeUnit.SECONDS);\n\n                        if (fb == null) {\n                            // not enough buffer space\n                            attach.updateLastOperation();\n                            readyChannelsQueue.offer(fdtSelectionKey);\n                            return 0;\n                        }\n\n                        boolean bRet = false;\n                        try {\n                            bRet = FDTWriterKeyAttachement.fromFileBlock(fb, attach);\n                        } finally {\n                            if (!bRet) {\n                                attach.recycleBuffers();\n                                if (fb != null && fb.buff != null) {\n                                    dbPool.put(fb.buff);\n                                    fb = null;\n                                }\n                            }\n                        }\n\n                    }\n                }\n\n                count = -1;\n                canWrite = (attach.payloadSize - attach.payload().position());\n\n                if (canWrite > bufferSize) {\n                    canWrite = bufferSize;\n                }\n\n                if (master.getRateLimit() > 0) {\n                    final long shouldWrite = master.awaitSend(canWrite);\n                    if (shouldWrite < canWrite) {\n                        canWrite = shouldWrite;\n                    }\n                    attach.payload().limit(attach.payload().position() + (int) canWrite);\n                }\n\n            }// end while()\n\n            if (count == 0) {\n                if (isNetTest && isBlocking) {\n                    final ByteBuffer buff = attach.payload();\n                    buff.position(0);\n                    buff.limit(buff.capacity());\n                    continue;\n                }\n\n                attach.payload().limit(attach.payloadSize);\n                fdtSelectionKey.renewInterest();\n                return count;\n\n                // if (fdtSelectionKey.opCount++ > RETRY_IO_COUNT) {\n                // if (isBlocking) {\n                // logger.log(Level.WARNING,\n                // \" reached RETRY_IO_COUNT in blocking mode ... remote peer down?! SC is blocking: \" +\n                // sc.isBlocking());\n                // master.workerDown(fdtSelectionKey, null);\n                // return count;\n                // }\n                //\n                // }\n\n                // continue;\n            }\n\n            // count < 0\n            attach.payload().limit(attach.payloadSize);\n            return count;\n\n        }\n\n        // return count;\n    }// writeData()\n\n    private void recycleBuffers() {\n        try {\n            final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.getAndSet(null);\n\n            if (fdtSelectionKey != null) {\n                FDTWriterKeyAttachement attach = (FDTWriterKeyAttachement) fdtSelectionKey.attachment();\n                if (attach != null) {\n                    attach.recycleBuffers();\n                }\n            }\n        } catch (Throwable t1) {\n            logger.log(Level.WARNING, \" Got exception trying to recover the buffers and returning them to pool\", t1);\n        }\n    }\n\n    public void internalClose() {\n        try {\n            final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.getAndSet(null);\n            if (fdtSelectionKey != null) {\n                fdtSelectionKey.cancel();\n                FDTWriterKeyAttachement attach = (FDTWriterKeyAttachement) fdtSelectionKey.attachment();\n\n                if (attach != null) {\n                    attach.recycleBuffers();\n                }\n\n                SocketChannel sc = fdtSelectionKey.channel();\n                try {\n                    sc.close();\n                } catch (Throwable t) {\n                }\n            }\n\n            if (fdtSelectionKey != null) {\n                master.workerDown(fdtSelectionKey, downCause());\n            } else {\n                master.workerDown(null, downCause());\n            }\n\n            recycleBuffers();\n        } catch (Throwable t1) {\n            System.err.println(\"\\n\\n\\n\\n\\\\n ========================= \\n\\n\\n\");\n            t1.printStackTrace();\n            System.err.println(\"\\n\\n\\n\\n\\\\n ========================= \\n\\n\\n\");\n        }\n    }\n\n    public void run() {\n\n        try {\n            for (; ; ) {\n                fdtSelectionKeyRef.set(null);\n                FDTSelectionKey iSel = null;\n                while (iSel == null) {\n                    fdtSelectionKeyRef.getAndSet(readyChannelsQueue.poll(2, TimeUnit.SECONDS));\n                    iSel = fdtSelectionKeyRef.get();\n                    if (isClosed()) {\n                        break;\n                    }\n                }\n\n                final FDTSelectionKey fdtSelectionKey = iSel;\n\n                if (isClosed())\n                    break;\n\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" writeDate for SK: \" + Utils.toStringSelectionKey(fdtSelectionKey) + \" SQSize : \" + readyChannelsQueue.size() + \" SelQueue: \" + readyChannelsQueue);\n                }\n\n                if (writeData() < 0 || master.isClosed()) {\n                    return;\n                }\n            }\n        } catch (Throwable t) {\n            final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.get();\n            master.workerDown(fdtSelectionKey, t);\n            close(\"SocketWriterTask got exception \", t);\n        } finally {\n            final FDTSelectionKey fdtSelectionKey = fdtSelectionKeyRef.getAndSet(null);\n\n            try {\n                if (fdtSelectionKey != null) {\n                    final FDTKeyAttachement attach = fdtSelectionKey.attachment();\n                    if (attach != null) {\n                        attach.recycleBuffers();\n                    }\n                }\n            } catch (Throwable t1) {\n                logger.log(Level.WARNING, \" Got exception trying to return buffers to the pool\", t1);\n            }\n            // *ALWAYS* return the buffer to the pool(s) whatever happens\n            master.workerDown(fdtSelectionKey, null);\n\n            close(null, null);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/SpeedLimitManager.java",
    "content": "/*\n * $Id$\n * Created on December 13, 2006, 11:16 AM\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Utils;\n\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class manages all the speed limits for FDTSession-s\n *\n * @author ramiro\n */\npublic class SpeedLimitManager {\n\n    private static final SpeedLimitManager _thisInstance = new SpeedLimitManager();\n\n    private static final Logger logger = Logger.getLogger(SpeedLimitManager.class.getName());\n\n    private final ScheduledThreadPoolExecutor executor;\n\n    /**\n     * Creates a new instance of LimitManager\n     */\n    private SpeedLimitManager() {\n        executor = Utils.getSchedExecService(\"SpeedLimitManager\", 2, Thread.MIN_PRIORITY + 1);\n    }\n\n    public static final SpeedLimitManager getInstance() {\n        return _thisInstance;\n    }\n\n    public ScheduledFuture<?> addLimiter(SpeedLimiter speedLimiter) throws Exception {\n        final long delay = speedLimiter.getNotifyDelay();\n        logger.log(Level.INFO, \" Adding SpeedLimiterTask for \" + speedLimiter + \" delay: \" + delay + \" ms\");\n        return executor.scheduleWithFixedDelay(new SpeedLimiterTask(speedLimiter), 0, delay, TimeUnit.MILLISECONDS);\n    }\n\n    private static final class SpeedLimiterTask implements Runnable {\n\n        final SpeedLimiter speedLimiter;\n\n        long lastUpdate;\n\n        private SpeedLimiterTask(SpeedLimiter speedLimiter) {\n            this.speedLimiter = speedLimiter;\n        }\n\n        public void run() {\n            try {\n                final long now = System.currentTimeMillis();\n                double newAvailable;\n\n                final long rateLimit = speedLimiter.getRateLimit();\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \"[ SpeedLimitManagerTask ] \" + speedLimiter + \" rateLimit: \" + rateLimit);\n                }\n                if (lastUpdate == 0) {\n                    newAvailable = rateLimit;\n                } else {\n                    newAvailable = rateLimit * ((now - lastUpdate) / 1000D);\n                }\n                lastUpdate = now;\n                if (logger.isLoggable(Level.FINER)) {\n                    logger.log(Level.FINER, \"[ SpeedLimitManagerTask ] \" + speedLimiter + \" av: \" + newAvailable);\n                }\n                speedLimiter.notifyAvailableBytes(Math.round(newAvailable));\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" SpeedLimiterTask got exception notifying \" + this.speedLimiter, t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/SpeedLimiter.java",
    "content": "/*\n * $Id$\n *\n * Created on December 14, 2006, 10:17 AM\n */\npackage lia.util.net.copy.transport;\n\n/**\n * The interface which all SpeedLimiter-s shoud implement...\n *\n * @author ramiro\n */\npublic interface SpeedLimiter {\n\n    /**\n     * returns the rate in Bytes/s\n     */\n    public long getRateLimit();\n\n    /**\n     * @return - how responsive/aggresive is the SpeedLimiter\n     */\n    public long getNotifyDelay();\n\n    public void notifyAvailableBytes(long availableBytes);\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/TCPSessionReader.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.FileBlockConsumer;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\nimport lia.util.net.copy.transport.internal.SelectionManager;\n\nimport java.net.InetAddress;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.SocketChannel;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This class provides the TransportProvider for a FDTSession which expects data from the wire.\n * It is responsible to stop all the sockets and notify it's session if something goes wrong\n * It also registers every worker in the SelectionManager with OP_READ interest\n *\n * @author ramiro\n */\npublic class TCPSessionReader extends TCPTransportProvider {\n\n    private static final Logger logger = Logger.getLogger(TCPSessionReader.class.getName());\n    private static final SelectionManager selectionManager = SelectionManager.getInstance();\n    private static final Config config = Config.getInstance();\n    private FileBlockConsumer fileBlockConsumer;\n\n    public TCPSessionReader(FDTSession fdtSession, FileBlockConsumer fileBlockConsumer) throws Exception {\n        super(fdtSession);\n        this.fileBlockConsumer = fileBlockConsumer;\n    }\n\n    public TCPSessionReader(FDTSession fdtSession,\n                            FileBlockConsumer fileBlockConsumer,\n                            InetAddress endPointAddress, int port,\n                            int numberOfStreams\n    ) throws Exception {\n\n        super(fdtSession, endPointAddress, port, numberOfStreams);\n        this.fileBlockConsumer = fileBlockConsumer;\n    }\n\n\n    public void addWorkerStream(SocketChannel sc, boolean sentCookie) throws Exception {\n        synchronized (this.closeLock) {\n            super.addWorkerStream(sc, sentCookie);\n            FDTSelectionKey fsk = null;\n\n            if (config.isBlocking()) {\n                fsk = new FDTSelectionKey(fdtSession.sessionID(), sc, SelectionKey.OP_READ, this, null);\n                fsk.attach(new FDTReaderKeyAttachement(fsk, fdtSession.useFixedBlockSize()));\n                selectionQueue.add(fsk);\n                SocketTask socketTask = new SocketReaderTask(selectionQueue, fileBlockConsumer, this);\n\n                if (addSocketTask(socketTask)) {\n                    executor.submit(socketTask);\n                } else {\n                    close(\"Unable to add a new SocketTask. OOM?\", null);\n                }\n\n            } else {\n                fsk = selectionManager.register(fdtSession.sessionID(), sc, SelectionKey.OP_READ, this);\n                fsk.attach(new FDTReaderKeyAttachement(fsk, fdtSession.useFixedBlockSize()));\n                if (!fsk.registerInterest()) {\n                    logger.log(Level.WARNING, \" \\n\\n Smth went terrible wrong ?? \\n\\n fsk.registerInterest() returned false \\n\\n\");\n                }\n            }\n\n            channels.put(sc, fsk);\n        }\n    }\n\n\n    //\n    //TODO - can we recover if downCause != null\n    //     - implement a timeout retry ? ... for the moment it just finishes the entire session\n    //     - this behavior should be changed when dynamic creation of workers will be added\n\n    /**\n     * @param fdtSelectionKey\n     * @param downCause\n     */\n    public void workerDown(FDTSelectionKey fdtSelectionKey, Throwable downCause) {\n        //smth gone wrong ... or maybe the session finished already\n        //I do not know if it should take other action ... for the moment the session will go down\n\n//        if(downCause != null) {\n//            logger.log(Level.WARNING, \" [ TCPSessionReader ] for fdtSession [ \" + fdtSession + \" ] got an error on a worker\", downCause);\n//        }\n//        \n//        close(downCause);\n    }\n\n    public void startTransport(boolean sendCookie) throws Exception {\n        super.startTransport(sendCookie);\n        synchronized (this.closeLock) {\n            if (!config.isBlocking()) {\n                for (int i = 0; i <= Utils.availableProcessors() * 2; i++) {\n                    SocketTask socketTask = new SocketReaderTask(selectionQueue, fileBlockConsumer, this);\n                    if (addSocketTask(socketTask)) {\n                        executor.submit(socketTask);\n                    } else {\n                        close(\"Unable to add a new SocketTask. OOM?\", null);\n                    }\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/TCPSessionWriter.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTReaderSession;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\nimport lia.util.net.copy.transport.internal.SelectionManager;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.SocketChannel;\nimport java.util.concurrent.PriorityBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n\n/**\n * The BIG \"limiter\" is here :)\n *\n * @author ramiro\n */\npublic class TCPSessionWriter extends TCPTransportProvider {\n\n    private static final Logger logger = Logger.getLogger(\"lia.util.net.copy.transport.TCPSessionWriter\");\n    private static final SelectionManager selectionManager = SelectionManager.getInstance();\n    private static final Config config = Config.getInstance();\n\n    public TCPSessionWriter(FDTReaderSession fdtSession) throws Exception {\n        super(fdtSession, new PriorityBlockingQueue<FDTSelectionKey>(10, new FDTWriterKeyAttachementComparator()));\n    }\n\n    public TCPSessionWriter(FDTReaderSession fdtSession,\n                            InetAddress endPointAddress, int port,\n                            int numberOfStreams) throws Exception {\n        super(fdtSession, endPointAddress, port, numberOfStreams, new PriorityBlockingQueue<FDTSelectionKey>(10, new FDTWriterKeyAttachementComparator()));\n    }\n\n    public void notifyAvailableBytes(final long available) {\n        speedLimitLock.lock();\n        try {\n            availableBytes = available;\n            isAvailable.signalAll();\n        } finally {\n            speedLimitLock.unlock();\n        }\n    }\n\n    public long awaitSend(final long bytesNo) throws InterruptedException {\n        long avForWrite = 0;\n        speedLimitLock.lock();\n        try {\n            while (avForWrite == 0 && !isClosed()) {\n                if (availableBytes > 0) {\n                    final long remainingBytes = availableBytes - bytesNo;\n\n                    if (remainingBytes >= 0) {\n                        availableBytes = remainingBytes;\n                        avForWrite = bytesNo;\n                        break;\n                    }\n\n                    avForWrite = availableBytes;\n                    availableBytes = 0;\n                } else {\n                    if (isAvailable.await(2, TimeUnit.SECONDS) && avForWrite > 0) {\n                        break;\n                    }\n                }\n            }\n        } finally {\n            speedLimitLock.unlock();\n        }\n\n        return avForWrite;\n    }\n\n    private int getMSS(SocketChannel sc) {\n\n        int retMSS = Config.NETWORK_BUFF_LEN_SIZE;\n\n        try {\n            final InetAddress ia = sc.socket().getLocalAddress();\n            NetworkInterface ni = NetworkInterface.getByInetAddress(ia);\n            int mss = ni.getMTU() - 40;\n            if (mss > 1000) {\n                retMSS = mss;\n            }\n        } catch (Throwable t) {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \"Cannot determine MTU for socket channel: \" + sc);\n            }\n        }\n\n        return retMSS;\n    }\n\n    public void addWorkerStream(SocketChannel sc, boolean sentCookie) throws Exception {\n        synchronized (this.closeLock) {\n            super.addWorkerStream(sc, sentCookie);\n            FDTSelectionKey fsk = null;\n\n            if (config.isBlocking()) {\n                fsk = new FDTSelectionKey(fdtSession.sessionID(), sc, SelectionKey.OP_WRITE, this, null);\n                fsk.attach(new FDTWriterKeyAttachement(fsk, fdtSession.useFixedBlockSize(), sentCookie));\n                executor.submit(new SocketWriterTask(selectionQueue, (FDTReaderSession) fdtSession, this));\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" BIO Mode. Adding SocketChannel \" + sc + \" to the selection queue\");\n                }\n                selectionQueue.add(fsk);\n            } else {\n                if (logger.isLoggable(Level.FINEST)) {\n                    logger.log(Level.FINEST, \" NBIO Mode. Adding SocketChannel \" + sc + \" to the SelectionManager! \");\n                }\n                fsk = selectionManager.register(fdtSession.sessionID(), sc, SelectionKey.OP_WRITE, this);\n                fsk.attach(new FDTWriterKeyAttachement(fsk, fdtSession.useFixedBlockSize(), sentCookie));\n                if (!fsk.registerInterest()) {\n                    logger.log(Level.WARNING, \" \\n\\n Smth went terrible wrong ?? \\n\\n fsk.registerInterest() returned false \\n\\n\");\n                }\n            }\n\n            final int mss = getMSS(sc);\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \" Setting MSS for: \" + sc + \" to: \" + mss);\n            }\n            fsk.setMSS(mss);\n\n            channels.put(sc, fsk);\n        }\n    }\n\n    public void startTransport(final boolean sendCookie) throws Exception {\n        super.startTransport(sendCookie);\n        if (!config.isBlocking()) {\n            for (int i = 0; i <= Utils.availableProcessors() * 2; i++) {\n                executor.submit(new SocketWriterTask(selectionQueue, (FDTReaderSession) fdtSession, this));\n            }\n        }\n    }\n\n    //\n    //TODO - can we recover if downCause != null\n    //     - implement a timeout retry ? ... for the moment it just finishes the entire session\n    //     - this behaviour should be changed when dynamic creation of workers will be added\n\n    /**\n     * @param fdtSelectionKey\n     */\n    public void workerDown(FDTSelectionKey fdtSelectionKey, Throwable downCause) {\n        //smth gone wrong ... or maybe the session finished already\n        //I do not know if it should take other action ... for the moment the session will go down\n        if (downCause != null) {\n            logger.log(Level.WARNING, \" [ TCPSessionReader ] for fdtSession [ \" + fdtSession + \" ] got an error on a worker\", downCause);\n        }\n\n        close(\"Worker down\", downCause);\n\n        if (fdtSession != null) {\n            try {\n                ((FDTReaderSession) fdtSession).transportWorkerDown();\n            } catch (Throwable ignore) {\n                //really don't care\n            }\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/TCPTransportProvider.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport;\n\nimport lia.util.net.common.AbstractFDTIOEntity;\nimport lia.util.net.common.Config;\nimport lia.util.net.common.DirectByteBufferPool;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.FDTSession;\nimport lia.util.net.copy.monitoring.NetSessionMonitoringTask;\nimport lia.util.net.copy.transport.internal.FDTSelectionKey;\nimport lia.util.net.copy.transport.internal.SelectionHandler;\nimport lia.util.net.copy.transport.internal.SelectionManager;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The base class for all read/write over the wire, and also has the \"SpeedLimiter\" incorporated, or not :)\n *\n * @author ramiro\n */\npublic abstract class TCPTransportProvider extends AbstractFDTIOEntity implements SelectionHandler, SpeedLimiter {\n\n    protected static final SelectionManager selectionManager = SelectionManager.getInstance();\n    private static final Logger logger = Logger.getLogger(TCPTransportProvider.class.getName());\n    private static final Config config = Config.getInstance();\n    protected final Lock speedLimitLock = new ReentrantLock(true);\n\n    protected final Condition isAvailable = speedLimitLock.newCondition();\n    // GuardedBy - this.closeLock\n    protected final HashMap<SocketChannel, FDTSelectionKey> channels = new HashMap<SocketChannel, FDTSelectionKey>();\n    protected final FDTSession fdtSession;\n    protected final ExecutorService executor;\n    protected final ArrayList<SocketTask> socketTasks = new ArrayList<SocketTask>();\n    protected final BlockingQueue<FDTSelectionKey> selectionQueue;\n    public NetSessionMonitoringTask monitoringTask;\n    protected long availableBytes;\n    protected InetAddress endPointAddress;\n    protected int port;\n    protected int numberOfStreams;\n    ScheduledFuture<?> monitoringTaskFuture;\n\n    ScheduledFuture<?> limiterTask;\n\n    public TCPTransportProvider(FDTSession fdtSession) throws Exception {\n        this(fdtSession, new LinkedBlockingQueue<FDTSelectionKey>());\n    }\n\n    public TCPTransportProvider(FDTSession fdtSession, BlockingQueue<FDTSelectionKey> selectionQueue) throws Exception {\n        this.fdtSession = fdtSession;\n        this.selectionQueue = selectionQueue;\n        executor = Utils.getStandardExecService(\" TCPTransportProvider task executor for FDTSession ( \" + fdtSession.sessionID() + \" )\", Utils.availableProcessors(), 4096, Thread.MAX_PRIORITY - 2);\n        if (!isClosed()) {\n            limiterTask = SpeedLimitManager.getInstance().addLimiter(this);\n        }\n    }\n\n    public TCPTransportProvider(FDTSession fdtSession, InetAddress endPointAddress, int port, int numberOfStreams) throws Exception {\n        this(fdtSession, endPointAddress, port, numberOfStreams, new LinkedBlockingQueue<FDTSelectionKey>());\n    }\n\n    public TCPTransportProvider(FDTSession fdtSession, InetAddress endPointAddress, int port, int numberOfStreams, BlockingQueue<FDTSelectionKey> selectionQueue) throws Exception {\n        this(fdtSession, selectionQueue);\n        this.endPointAddress = endPointAddress;\n        this.port = port;\n        this.numberOfStreams = numberOfStreams;\n    }\n\n    private static final List<SocketChannel> tryToConnect(InetSocketAddress addr, int numberOfStreams, ByteBuffer connectCookie, final boolean sendCookie) throws Exception {\n\n        if (addr == null) {\n            throw new NullPointerException(\"Address cannot be null\");\n        }\n        if (numberOfStreams <= 0) {\n            throw new IllegalArgumentException(\"Number of streams must be > 0 ( \" + numberOfStreams + \")\");\n        }\n        ArrayList<SocketChannel> tmpChannels = new ArrayList<SocketChannel>();\n\n        // use a temporary selector to wait for sockets to finish their connect()\n        Selector tmpSelector = null;\n        ArrayList<SocketChannel> connectedChannels = new ArrayList<SocketChannel>();\n\n        try {\n            int windowSize = config.getSockBufSize();\n            boolean noDelay = config.isNagleEnabled();\n            int usedWindowSize = -1;\n\n            tmpSelector = Selector.open();\n\n            final int bSockConn = Config.getBulkSockConnect();\n            final long bSockConnWait = Config.getBulkSockConnectWait();\n\n            logger.log(Level.FINER, \" bSockConn: \" + bSockConn + \" bSockConnWait: \" + bSockConnWait);\n            int cCounter = 0;\n            for (int i = 0; i < numberOfStreams; i++) {\n\n                if (bSockConn > 0 && cCounter > bSockConn) {\n                    try {\n                        final long sTime = (bSockConnWait > 100) ? bSockConnWait : 1000;\n                        logger.log(Level.INFO, \" connected \" + i + \" sockets. sleeping \" + sTime + \" ms\");\n                        Thread.sleep(sTime);\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \" Exception trying to wait for bulk connections\", t);\n                    }\n                    cCounter = 0;\n                }\n\n                cCounter++;\n                final SocketChannel sc = SocketChannel.open();\n\n                sc.configureBlocking(config.isBlocking());\n\n                sc.connect(addr);\n                tmpChannels.add(sc);\n\n                final Socket s = sc.socket();\n\n                if (windowSize > 0) {\n                    s.setSendBufferSize(windowSize);\n                }\n                final String sdpConfFlag = System.getProperty(\"com.sun.sdp.conf\");\n                final boolean bSDP = (sdpConfFlag != null && !sdpConfFlag.isEmpty());\n\n                if (!bSDP) {\n                    try {\n                        s.setKeepAlive(true);\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Cannot set KEEP_ALIVE for \" + sc + \". Will ignore the error. Contact your sys admin.\", t);\n                    }\n\n                    try {\n                        //IPTOS_LOWCOST (0x02) IPTOS_RELIABILITY (0x04) IPTOS_THROUGHPUT (0x08) IPTOS_LOWDELAY (0x10)\n                        s.setTrafficClass(0x04 | 0x08 | 0x010);\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \"[ FDTServer ] [ AcceptableTask ] Cannot set traffic class for \" + sc + \"[ IPTOS_RELIABILITY (0x04) | IPTOS_THROUGHPUT (0x08) | IPTOS_LOWDELAY (0x10) ] Will ignore the error. Contact your sys admin.\", t);\n                    }\n                }\n\n                if (!sc.isBlocking()) {\n                    sc.register(tmpSelector, SelectionKey.OP_CONNECT | SelectionKey.OP_WRITE);\n                } else {\n                    sc.finishConnect();\n\n                    usedWindowSize = sc.socket().getSendBufferSize();\n\n                    if (!sendCookie) {\n                        connectedChannels.add(sc);\n                    } else {\n                        if (connectCookie != null) {\n                            if (sc.write(connectCookie) >= 0 && !connectCookie.hasRemaining()) {\n                                connectedChannels.add(sc);\n                            } else {\n                                throw new IOException(\"Cannot connect\");\n                            }\n                            connectCookie.flip();\n                        }\n                    }\n                }\n            }\n\n            int i = 0;\n\n            // CONNECT\n            while (tmpChannels.size() != connectedChannels.size()) {\n                int n = tmpSelector.select();\n\n                if (n == 0) {\n                    continue;\n                }\n                Set<SelectionKey> selectedKeys = tmpSelector.selectedKeys();\n\n                for (Iterator<SelectionKey> it = selectedKeys.iterator(); it.hasNext(); ) {\n                    SelectionKey ssk = it.next();\n                    it.remove();\n                    SocketChannel sc = (SocketChannel) ssk.channel();\n                    if (ssk.isConnectable()) {\n                        ssk.interestOps(ssk.interestOps() & ~SelectionKey.OP_CONNECT);\n                        while (!sc.finishConnect()) {\n                            System.out.println(\"Socket not yet connected!!!\");\n                            Thread.yield();\n                        }\n                    } else {\n                        try {\n                            if (noDelay) {\n                                sc.socket().setTcpNoDelay(true);\n                            }\n                        } catch (Throwable t) {\n                            logger.log(Level.WARNING, \" Cannot enable/disable Nagle's alg\", t);\n                        }\n\n                        try {\n                            sc.socket().setKeepAlive(true);\n                        } catch (Throwable t) {\n                            logger.log(Level.WARNING, \" Cannot set KEEP_ALIVE\", t);\n                        }\n\n                        usedWindowSize = sc.socket().getSendBufferSize();\n\n                        ssk.interestOps(ssk.interestOps() & ~SelectionKey.OP_WRITE);\n                        if (sendCookie && connectCookie != null) {\n                            while (sc.write(connectCookie) >= 0 && connectCookie.hasRemaining()) {\n                                Thread.yield();\n                            }\n                            connectCookie.flip();\n                        }\n                        i++;\n                        if (logger.isLoggable(Level.FINE)) {\n                            logger.log(Level.FINE, \"Connection ( \" + i + \" ) established [ \" + sc.socket().getLocalAddress() + \":\" + sc.socket().getLocalPort() + \" -> \" + sc.socket().getInetAddress() + \":\" + sc.socket().getPort() + \" ]\");\n                        }\n\n                        connectedChannels.add(sc);\n                    }\n                }\n            }\n\n            logger.log(Level.INFO, \"Requested window size \" + windowSize + \". Using window size: \" + usedWindowSize);\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Unable to connect to \" + addr.toString(), t);\n            for (SocketChannel sc : tmpChannels) {\n                try {\n                    sc.close();\n                } catch (Throwable t1) {\n                    // ignore\n                }\n            }\n\n            throw new Exception(t);\n        } finally {\n            if (tmpSelector != null) {\n                try {\n                    tmpSelector.close();\n                } catch (Throwable ingnore) { // ignore\n                }\n            }\n        }\n\n        return tmpChannels;\n    }\n\n    public final boolean useFixedBlockSize() {\n        return fdtSession.useFixedBlockSize();\n    }\n\n    public final boolean localLoop() {\n        return fdtSession.localLoop();\n    }\n\n    public final boolean isNetTest() {\n        return fdtSession.isNetTest();\n    }\n\n    public long getSize() {\n        return -1;\n    }\n\n    public long getNotifyDelay() {\n        return fdtSession.getRateLimitDelay();\n    }\n\n    public void notifyAvailableBytes(long available) {\n    }\n\n    public final long getRateLimit() {\n        return fdtSession.getRateLimit();\n    }\n\n    public int getNumberOfStreams() {\n        synchronized (this.closeLock) {\n            return channels.size();\n        }\n    }\n\n    public InetAddress getRemoteEndPointAddress() {\n        return null;\n    }\n\n    public FDTSession getSession() {\n        return fdtSession;\n    }\n\n    private final void clearSelectionQueue() {\n        try {\n            FDTSelectionKey fsk = selectionQueue.poll();\n            while (fsk != null) {\n                FDTKeyAttachement attachment = fsk.attachment();\n                if (attachment != null) {\n                    attachment.recycleBuffers();\n                }\n                fsk = selectionQueue.poll();\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception\", t);\n        }\n    }\n\n    protected void internalClose() {\n\n        if (limiterTask != null) {\n            limiterTask.cancel(true);\n        }\n\n        if (monitoringTaskFuture != null) {\n            monitoringTaskFuture.cancel(false);\n        }\n\n        if (monitoringTask != null) {\n            ScheduledThreadPoolExecutor monitoringService = Utils.getMonitoringExecService();\n            monitoringService.remove(monitoringTask);\n            monitoringService.purge();\n        }\n\n        // be nice ... will be more aggressive a little bit later\n        if (executor != null) {\n            executor.shutdown();\n        }\n\n        if (fdtSession != null) {\n            fdtSession.close(downMessage(), downCause());\n        }\n\n        for (Map.Entry<SocketChannel, FDTSelectionKey> entry : channels.entrySet()) {\n            final SocketChannel sc = entry.getKey();\n            final FDTSelectionKey fdtSelKey = entry.getValue();\n\n            try {\n                final FDTKeyAttachement attach = fdtSelKey.attachment();\n                if (attach != null) {\n                    attach.recycleBuffers();\n                }\n            } catch (Throwable t) {\n                // ignore closing exceptions ...\n            }\n\n            try {\n                sc.close();\n            } catch (Throwable t) {\n                // ignore closing exceptions ...\n            }\n\n            try {\n                fdtSelKey.cancel();\n            } catch (Throwable t) {\n                // ignore closing exceptions ...\n            }\n\n        }\n        channels.clear();\n\n        synchronized (socketTasks) {\n            for (SocketTask st : socketTasks) {\n                try {\n                    st.close(downMessage(), downCause());\n                } catch (Throwable ignore) {\n                }\n            }\n\n            socketTasks.clear();\n        }\n\n        clearSelectionQueue();\n    }\n\n    protected boolean addSocketTask(SocketTask socketTask) {\n        synchronized (socketTasks) {\n            if (isClosed()) {\n                socketTask.close(downMessage(), downCause());\n                return false;\n            }\n            return socketTasks.add(socketTask);\n        }\n    }\n\n    public void startTransport(boolean sendCookie) throws Exception {\n        if (endPointAddress != null) {\n            InetSocketAddress addr = new InetSocketAddress(endPointAddress, port);\n\n            ByteBuffer connectCookie = null;\n            DirectByteBufferPool instance = DirectByteBufferPool.getInstance();\n            try {\n                connectCookie = instance.take();\n                connectCookie.limit(1 + 16);\n                connectCookie.put((byte) 1).putLong(fdtSession.sessionID().getMostSignificantBits()).putLong(fdtSession.sessionID().getLeastSignificantBits());\n                connectCookie.flip();\n                addChannels(tryToConnect(addr, numberOfStreams, connectCookie, sendCookie), sendCookie);\n            } finally {\n                if (connectCookie != null) {\n                    instance.put(connectCookie);\n                }\n            }\n        }\n\n    }\n\n    public void addChannels(List<SocketChannel> channels, boolean sentCookie) throws Exception {\n        if (isClosed()) {\n            throw new FDTProcolException(\"The transport provider is down\");\n        }\n        synchronized (this.closeLock) {\n            for (final SocketChannel sc : channels) {\n                addWorkerStream(sc, sentCookie);\n            }\n        }\n    }\n\n    public void handleSelection(FDTSelectionKey fdtSelectionKey) {\n        if (logger.isLoggable(Level.FINEST)) {\n            logger.log(Level.FINEST, \" [ TCPTransportProvider ]  [ SELECTION ] [ NBIO ] handle selection for \" + Utils.toStringSelectionKey(fdtSelectionKey));\n        }\n        selectionQueue.add(fdtSelectionKey);\n    }\n\n    public void canceled(FDTSelectionKey fdtSelectionKey) {\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"  [ SELECTION ] [ NBIO ] Canceled event for \" + fdtSelectionKey);\n        }\n\n        SocketChannel sc = fdtSelectionKey.channel();\n        try {\n            sc.close();\n        } catch (Throwable ignore) {\n            if (logger.isLoggable(Level.FINE)) {\n                logger.log(Level.FINE, \" Got exception closing socket \" + sc, ignore);\n            }\n        }\n\n        FDTKeyAttachement attachement = fdtSelectionKey.attachment();\n        if (attachement != null) {\n            attachement.recycleBuffers();\n        } else {\n            logger.log(Level.WARNING, \" Null attachement for fdtSelectionKey: \" + fdtSelectionKey + \" sc: \" + sc);\n        }\n    }\n\n    public void addWorkerStream(SocketChannel channel, boolean sentCookie) throws Exception {\n        final ScheduledExecutorService monitoringService = Utils.getMonitoringExecService();\n        synchronized (closeLock) {\n            if (monitoringTaskFuture == null && !closed) {\n                this.monitoringTask = new NetSessionMonitoringTask(this);\n                monitoringTaskFuture = monitoringService.scheduleWithFixedDelay(monitoringTask, 1, 1, TimeUnit.SECONDS);\n            }\n\n            if (logger.isLoggable(Level.FINER)) {\n                logger.log(Level.FINER, \" TCPTransportProvider add working stream for channel: \" + channel);\n            }\n\n            this.channels.put(channel, null);\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/gui/FileHandler.java",
    "content": "/*\n * $Id$\n * Created on Aug 20, 2007\n *\n * moved from lia.util.net.copy.gui\n */\npackage lia.util.net.copy.transport.gui;\n\nimport java.io.Serializable;\n\n/**\n * @author Ciprian Dobre\n * The serializable object representing the properties of a file...\n */\npublic class FileHandler implements Serializable {\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n    /**\n     * The name of the file or folder\n     */\n    private final String name;\n    /**\n     * The last time it was modified\n     */\n    private final long modif;\n    /**\n     * The length of the file, should be -1 if folder\n     */\n    private final long size;\n    /**\n     * Read flag is set ?\n     */\n    private final boolean read;\n    /**\n     * Write flag is set ?\n     */\n    private final boolean write;\n\n    public FileHandler(String name, long modif, long size, boolean read, boolean write) {\n        this.name = name;\n        this.modif = modif;\n        this.size = size;\n        this.read = read;\n        this.write = write;\n    }\n\n    public final String getName() {\n        return name;\n    }\n\n    public final long getModif() {\n        return modif;\n    }\n\n    public final long getSize() {\n        return size;\n    }\n\n    public final boolean canRead() {\n        return read;\n    }\n\n    public final boolean canWrite() {\n        return write;\n    }\n}"
  },
  {
    "path": "src/lia/util/net/copy/transport/gui/GUIControlChannel.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport.gui;\n\nimport lia.util.net.common.AbstractFDTCloseable;\nimport lia.util.net.common.Config;\nimport lia.util.net.copy.transport.CtrlMsg;\nimport lia.util.net.copy.transport.FDTProcolException;\n\nimport java.io.*;\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.concurrent.ConcurrentLinkedQueue;\n\n/**\n * A special control channel used to transport only GUI messages - on the client side of the connection.\n *\n * @author Ciprian Dobre\n */\npublic class GUIControlChannel extends AbstractFDTCloseable implements Runnable {\n\n    public static final int CONNECT_TIMEOUT = 20 * 1000;\n    private static final CtrlMsg versionMsg = new CtrlMsg(CtrlMsg.PROTOCOL_VERSION, Config.FDT_FULL_VERSION + \"-\" + Config.FDT_RELEASE_DATE);\n    public final InetAddress remoteAddress;\n    public final int remotePort;\n    public final int localPort;\n    private GUIControlChannelNotifier notifier;\n    private Socket controlSocket;\n    private ObjectOutputStream oos = null;\n    private ObjectInputStream ois = null;\n    private ConcurrentLinkedQueue<Object> qToSend = new ConcurrentLinkedQueue<Object>();\n\n    /**\n     * Try to connect to a remote FDT instance\n     *\n     * @param address\n     * @param port\n     * @param notifier\n     * @throws Exception\n     */\n    public GUIControlChannel(String address, int port, GUIControlChannelNotifier notifier) throws Exception {\n        this(InetAddress.getByName(address), port, notifier);\n    }\n\n    /**\n     * Try to connect to a remote FDT instance\n     *\n     * @param inetAddress\n     * @param port\n     * @param notifier\n     * @throws Exception\n     */\n    public GUIControlChannel(InetAddress inetAddress, int port, GUIControlChannelNotifier notifier) throws Exception {\n        try {\n            this.notifier = notifier;\n\n            controlSocket = new Socket();\n            controlSocket.connect(new InetSocketAddress(inetAddress, port), CONNECT_TIMEOUT);\n\n            this.remoteAddress = inetAddress;\n            this.remotePort = port;\n            this.localPort = controlSocket.getLocalPort();\n\n            controlSocket.setTcpNoDelay(true);\n\n            //only the first octet will be interpreted by the AcceptTask at the other end\n            controlSocket.getOutputStream().write(new byte[]{3});\n\n            //from now on only CtrlMsg will be sent\n            initStreams();\n            controlSocket.setSoTimeout(1000);\n\n            //\n        } catch (Throwable t) {\n            close(\"Cannot instantiate ControlChannel\", t);\n            throw new Exception(t);\n        }\n    }\n\n    public String toString() {\n        return (controlSocket == null) ? \"null\" : controlSocket.toString();\n    }\n\n    private void initStreams() throws Exception {\n        oos = new ObjectOutputStream(new BufferedOutputStream(controlSocket.getOutputStream()));\n        //send the version\n\n        sendMsgImpl(versionMsg);\n\n        ois = new ObjectInputStream(new BufferedInputStream(controlSocket.getInputStream()));\n\n        //wait for remote version\n        CtrlMsg ctrlMsg = (CtrlMsg) ois.readObject();\n        if (ctrlMsg.tag != CtrlMsg.PROTOCOL_VERSION) {\n            throw new FDTProcolException(\"Unexpected remote control message. Expected PROTOCOL_VERSION tag [ \" + CtrlMsg.PROTOCOL_VERSION + \" ] Received tag: \" + ctrlMsg.tag);\n        }\n\n        Object o = ois.readObject(); // read the working dir\n        notifier.notifyCtrlMsg(this, o);\n        o = ois.readObject(); // read the user home\n        notifier.notifyCtrlMsg(this, o);\n        o = ois.readObject(); // read the os name\n        notifier.notifyCtrlMsg(this, o);\n        o = ois.readObject(); // read the list of files\n        notifier.notifyCtrlMsg(this, o);\n        o = ois.readObject(); // read the current roots\n        notifier.notifyCtrlMsg(this, o);\n    }\n\n    private void cleanup() {\n        if (ois != null) {\n            try {\n                ois.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            ois = null;\n        }\n\n        if (oos != null) {\n            try {\n                oos.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            oos = null;\n        }\n\n        if (controlSocket != null) {\n            try {\n                controlSocket.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            controlSocket = null;\n        }\n    }\n\n    public void sendCtrlMessage(Object ctrlMsg) throws IOException, FDTProcolException {\n\n        if (isClosed() && controlSocket != null && !controlSocket.isClosed()) {\n            throw new FDTProcolException(\"Control channel already closed\");\n        }\n\n        qToSend.add(ctrlMsg);\n    }\n\n    public boolean isClosed() {\n        return super.isClosed() || controlSocket == null || controlSocket.isClosed();\n    }\n\n    private void sendAllMsgs() throws Exception {\n        for (; ; ) {\n            Object ctrlMsg = qToSend.poll();\n            if (ctrlMsg == null) break;\n            sendMsgImpl(ctrlMsg);\n        }\n    }\n\n    private void sendMsgImpl(Object o) throws Exception {\n        try {\n            oos.writeObject(o);\n            oos.reset();//DO NOT CACHE!\n            oos.flush();\n        } catch (Throwable t) {\n            close(\"Exception sending control data\", t);\n            throw new IOException(\" Cannot send ctrl message ( \" + t.getCause() + \" ) \");\n        }\n    }\n\n    public void run() {\n        try {\n            while (!isClosed()) {\n                try {\n                    sendAllMsgs();\n                    Object o = ois.readObject();\n                    if (o == null) continue;\n                    notifier.notifyCtrlMsg(this, o);\n                } catch (SocketTimeoutException ste) {\n                    //ignore this??? or shall I close it() ?\n                } catch (FDTProcolException fdte) {\n                    close(\"FDTProtocolException\", fdte);\n                }\n            }\n\n        } catch (Throwable t) {\n            close(null, t);\n        }\n    }\n\n    protected void internalClose() {\n        try {\n            cleanup();\n        } catch (Throwable ignore) {\n        }\n\n        try {\n            if (notifier != null) {\n                notifier.notifyCtrlSessionDown(this, downCause());\n            }\n        } catch (Throwable ignore) {\n        }\n    }\n\n} // end of class GUIControlChannel\n\n\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/gui/GUIControlChannelNotifier.java",
    "content": "package lia.util.net.copy.transport.gui;\n\nimport lia.util.net.copy.transport.FDTProcolException;\n\n/**\n * An interface to be used for signaling between session and gui\n *\n * @author Ciprian Dobre\n */\npublic interface GUIControlChannelNotifier {\n\n    public void notifyCtrlMsg(GUIControlChannel controlChannel, Object ctrlMessage) throws FDTProcolException;\n\n    public void notifyCtrlSessionDown(GUIControlChannel controlChannel, Throwable cause) throws FDTProcolException;\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/gui/GUIMessage.java",
    "content": "/*\n * $Id$\n * Created on Aug 20, 2007\n *\n * moved from lia.util.net.copy.gui\n */\npackage lia.util.net.copy.transport.gui;\n\nimport java.io.Serializable;\n\n/**\n * @author Ciprian Dobre\n */\npublic class GUIMessage implements Serializable {\n    /**\n     * <code>serialVersionUID</code>\n     */\n    private static final long serialVersionUID = 1988671591829311032L;\n    /**\n     * The tag of the message\n     */\n    private final int mID;\n    /**\n     * The message\n     */\n    private final Object msg;\n\n    /**\n     * Possible exception\n     */\n    private final Exception e;\n\n    public GUIMessage(int mID, Object msg) {\n        this.mID = mID;\n        this.msg = msg;\n        this.e = null;\n    }\n\n    public GUIMessage(int mID, Object msg, Exception e) {\n        this.mID = mID;\n        this.msg = msg;\n        this.e = e;\n    }\n\n    public final int getMID() {\n        return mID;\n    }\n\n    public final Object getMsg() {\n        return msg;\n    }\n\n    public final Exception getException() {\n        return e;\n    }\n}"
  },
  {
    "path": "src/lia/util/net/copy/transport/gui/ServerSessionManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport.gui;\n\nimport lia.util.net.common.AbstractFDTCloseable;\nimport lia.util.net.common.Config;\nimport lia.util.net.copy.transport.ControlChannel;\nimport lia.util.net.copy.transport.CtrlMsg;\nimport lia.util.net.copy.transport.FDTProcolException;\n\nimport javax.swing.filechooser.*;\nimport java.io.*;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * The manager that handler the local FS on the server side of the communication, it should be interrogated in order\n * to fill the methods and data of RemoteSessionManager\n *\n * @author Ciprian Dobre\n */\npublic class ServerSessionManager extends AbstractFDTCloseable implements Runnable {\n\n    private static final CtrlMsg versionMsg = new CtrlMsg(CtrlMsg.PROTOCOL_VERSION, Config.FDT_FULL_VERSION + \"-\" + Config.FDT_RELEASE_DATE);\n    private static final Logger logger = Logger.getLogger(ControlChannel.class.getName());\n    private static FileSystemView local = FileSystemView.getFileSystemView();\n    public final InetAddress remoteAddress;\n    public final int remotePort;\n    public final int localPort;\n    protected final Vector<FileHandler> currentFiles = new Vector<FileHandler>();\n    // helper mapping between display names and real File folders used for root folders\n    private final HashMap<String, File> roots = new HashMap<String, File>();\n    private final HashMap<String, String> h = new HashMap<String, String>();\n    /**\n     * The current working directory\n     */\n    public String currentDir;\n    /**\n     * The name of the operating system\n     */\n    public String osName;\n    /**\n     * The file separator\n     */\n    public String fileSeparator;\n    /**\n     * The default directory of the user\n     */\n    public String userDir;\n    private File currentFile;\n    private boolean canWrite;\n    private Socket controlSocket;\n    private ObjectOutputStream oos = null;\n    private ObjectInputStream ois = null;\n    private ConcurrentLinkedQueue<Object> qToSend = new ConcurrentLinkedQueue<Object>();\n\n    public ServerSessionManager(Socket s) throws Exception {\n        currentFile = local.getHomeDirectory();\n        this.currentDir = currentFile.getAbsolutePath();\n        osName = System.getProperty(\"os.name\");\n        userDir = System.getProperty(\"user.home\");\n        fileSeparator = System.getProperty(\"file.separator\");\n        update();\n        try {\n            this.controlSocket = s;\n            this.remoteAddress = s.getInetAddress();\n            this.remotePort = s.getPort();\n            this.localPort = s.getLocalPort();\n            initStreams();\n            controlSocket.setSoTimeout(1000);\n        } catch (Throwable t) {\n            close(\"Cannot instantiate ControlChannel\", t);\n            throw new Exception(t);\n        }\n    }\n\n    public void setAbsoluteDir(String dir) {\n        if (dir == null) return;\n        dir = getRoot(dir);\n        if (roots.containsKey(dir)) {\n            currentFile = roots.get(dir);\n            currentDir = currentFile.getAbsolutePath();\n            update();\n            return;\n        }\n        try {\n            File f = new File(dir);\n            if (!f.exists() || !f.isDirectory() || !f.canRead()) return;\n            currentFile = f;\n            currentDir = currentFile.getAbsolutePath();\n            update();\n        } catch (Exception e) {\n        }\n    }\n\n    private final String getRoot(String dir) {\n        if (roots.containsKey(dir)) return dir;\n        for (Map.Entry<String, File> entry : roots.entrySet()) {\n            if (entry.getValue().getAbsolutePath().equals(dir)) return entry.getKey();\n        }\n        return dir;\n    }\n\n    public void setRelativeDir(String dir) {\n        File f = local.getChild(currentFile, dir);\n        if (f == null || !f.exists() || !f.isDirectory()) return; // error, cannot change\n        currentFile = f;\n        currentDir = f.getAbsolutePath();\n        update();\n    }\n\n    public void setUpDir() {\n        File f = local.getParentDirectory(currentFile);\n        if (f == null || !f.exists() || !f.isDirectory()) return; // error, cannot change\n        currentFile = f;\n        currentDir = f.getAbsolutePath();\n        update();\n    }\n\n    public String[] getRoots() {\n        roots.clear(); // clear the previously discovered roots\n        // auxiliary hash used\n        final HashSet<String> h = new HashSet<String>();\n        // start by using the FileSystemView...\n        File roots[] = local.getRoots();\n        if (roots != null) {\n            for (int i = 0; i < roots.length; i++) {\n                String displayName = local.getSystemDisplayName(roots[i]);\n                if (h.contains(displayName)) continue; // do not add it twice\n                if (displayName.length() == 0)\n                    continue; // skip empty drives (it applies to cd drives and floppy drives without media\n                h.add(displayName);\n                this.roots.put(displayName, roots[i]);\n            }\n        }\n        // then use the File object....\n        roots = File.listRoots();\n        if (roots != null) {\n            for (int i = 0; i < roots.length; i++) {\n                String displayName = local.getSystemDisplayName(roots[i]);\n                if (h.contains(displayName)) continue; // do not add it twice\n                if (displayName.length() == 0)\n                    continue; // skip empty drives (it applies to cd drives and floppy drives without media\n                h.add(displayName);\n                this.roots.put(displayName, roots[i]);\n            }\n        }\n        // also if linux put the path to the home directory...\n        if (System.getProperty(\"os.name\").toLowerCase(Locale.US).contains(\"linux\")) {\n            String p = System.getProperty(\"user.home\");\n            File f = new File(p);\n            if (f.exists()) {\n                File pa = null;\n                while ((pa = f.getParentFile()) != null && pa.exists()) {\n                    this.roots.put(f.getAbsolutePath(), f);\n                    f = pa;\n                }\n            }\n        }\n        final String[] keys = new String[this.roots.size()];\n        int i = 0;\n        for (Iterator<String> it = this.roots.keySet().iterator(); it.hasNext() && i < keys.length; i++) {\n            keys[i] = it.next();\n        }\n        return keys;\n    }\n\n    public String getShortRootName(String rootFolder) {\n        if (rootFolder == null) return null;\n        rootFolder = getRoot(rootFolder);\n        if (roots.containsKey(rootFolder)) return roots.get(rootFolder).getAbsolutePath();\n        return null;\n    }\n\n    public boolean isRoot() {\n        if (local.isDrive(currentFile)) {\n            return true;\n        }\n        File f = local.getParentDirectory(currentFile);\n        return f == null;\n    }\n\n    protected void update() {\n        currentFiles.clear();\n        // list the current files\n        File l[] = local.getFiles(currentFile, false);\n        if (l != null) {\n            for (int i = 0; i < l.length; i++) {\n                String fn = local.getSystemDisplayName(l[i]);\n                if (fn.length() == 0) continue;\n                if (l[i].isDirectory()) {\n                    // check to see if we are not looking at some links...\n                    try {\n                        File tmpf = local.getChild(currentFile, fn);\n                        if (tmpf == null || !local.isTraversable(tmpf)) continue; // alarm, link detected here\n                        local.getFiles(tmpf, false);\n                    } catch (Throwable t) {\n                        continue;\n                    }\n                    // otherwise is ok to add it...\n                    currentFiles.add(new FileHandler(fn, l[i].lastModified(), -1L, l[i].canRead(), l[i].canWrite()));\n                } else if (l[i].isFile()) {\n                    currentFiles.add(new FileHandler(fn, l[i].lastModified(), l[i].length(), l[i].canRead(), l[i].canWrite()));\n                }\n            }\n        }\n        try {\n            int i = 0;\n            while (true) {\n                File f = new File(currentDir + System.getProperty(\"file.separator\") + \"fdt\" + i);\n                if (f.exists()) continue;\n                f.createNewFile();\n                canWrite = f.exists();\n                if (canWrite)\n                    f.delete();\n                break;\n            }\n        } catch (Throwable t) {\n            canWrite = false;\n        }\n    }\n\n    /**\n     * Message comming from the other end of the connection...\n     */\n    public void process(Object o) throws Exception {\n        if (!(o instanceof CtrlMsg)) return;\n        CtrlMsg msg = (CtrlMsg) o;\n        if (msg.tag != CtrlMsg.GUI_MSG) return; // only this type of message can be processed here\n        GUIMessage m = (GUIMessage) msg.message;\n        switch (m.getMID()) {\n            case 0: // request for current directory...\n            {\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(0, new Object[]{getWorkingDirectory(), canWrite}));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 1: // request for user home\n            {\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(1, getUserHome()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 2: // request for os name\n            {\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(2, getOSName()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 3: // request for current files\n            {\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 4: // request for the current roots\n            {\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(4, getRoots()));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(9, formShortNames()));\n                sendCtrlMessage(c);\n                break;\n            }\n//\t\tcase 5: // is root request\n//\t\t{\n//\t\t\tCtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(5, Boolean.valueOf(isRoot())));\n//\t\t\tsendCtrlMessage(c);\n//\t\t\tbreak;\n//\t\t}\n            case 6: // set absolute dir\n            {\n                String dir = (String) m.getMsg();\n                setAbsoluteDir(dir);\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(5, Boolean.valueOf(isRoot())));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(12, freeSpace()));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(0, new Object[]{getWorkingDirectory(), canWrite}));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 7: // set relative dir\n            {\n                String dir = (String) m.getMsg();\n                setRelativeDir(dir);\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(5, Boolean.valueOf(isRoot())));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(12, freeSpace()));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(0, new Object[]{getWorkingDirectory(), canWrite}));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 8: // set up dir\n            {\n                setUpDir();\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(5, Boolean.valueOf(isRoot())));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(12, freeSpace()));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(0, new Object[]{getWorkingDirectory(), canWrite}));\n                sendCtrlMessage(c);\n                c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 10: // remove files\n            {\n                String files[] = (String[]) m.getMsg();\n                removeFiles(files);\n                CtrlMsg c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                sendCtrlMessage(c);\n                break;\n            }\n            case 11: // create dir\n            {\n                String name = (String) m.getMsg();\n                CtrlMsg c = null;\n                try {\n                    createDir(name);\n                    c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList()));\n                } catch (Exception e) {\n                    c = new CtrlMsg(CtrlMsg.GUI_MSG, new GUIMessage(3, getFileList(), e));\n                }\n                sendCtrlMessage(c);\n                break;\n            }\n        }\n    }\n\n    /**\n     * Returns the current directory of the session.. (default user home)\n     */\n    public String getWorkingDirectory() {\n        return currentDir;\n    }\n\n    /**\n     * Returns the directory home of the user\n     */\n    public String getUserHome() {\n        return userDir;\n    }\n\n    /**\n     * Returns the name of the operating system\n     */\n    public String getOSName() {\n        return osName;\n    }\n\n    public String getFileSeparator() {\n        return fileSeparator;\n    }\n\n    /**\n     * Returns the list of current files and folder in the current directory of the session\n     */\n    public Vector<FileHandler> getFileList() {\n        return currentFiles;\n    }\n\n    public void removeFiles(String[] files) {\n        if (files == null) return;\n        for (int i = 0; i < files.length; i++) {\n            try {\n                File f = new File(files[i]);\n                if (f.isDirectory()) {\n                    File ff[] = f.listFiles();\n                    if (ff != null) {\n                        String str[] = new String[ff.length];\n                        for (int j = 0; j < str.length; j++) {\n                            str[j] = ff[j].getAbsolutePath();\n                        }\n                        removeFiles(str);\n                    }\n                }\n                f.delete();\n            } catch (Throwable t) {\n            }\n        }\n        update();\n    }\n\n    public void createDir(String name) throws Exception {\n        if (name == null) return;\n        File f = new File(name);\n        f.mkdirs();\n        update();\n    }\n\n    private void initStreams() throws Exception {\n        oos = new ObjectOutputStream(new BufferedOutputStream(controlSocket.getOutputStream()));\n        //send the version\n\n        sendMsgImpl(versionMsg);\n\n        ois = new ObjectInputStream(new BufferedInputStream(controlSocket.getInputStream()));\n\n        //wait for remote version\n        CtrlMsg ctrlMsg = (CtrlMsg) ois.readObject();\n        if (ctrlMsg.tag != CtrlMsg.PROTOCOL_VERSION) {\n            throw new FDTProcolException(\"Unexpected remote control message. Expected PROTOCOL_VERSION tag [ \" + CtrlMsg.PROTOCOL_VERSION + \" ] Received tag: \" + ctrlMsg.tag);\n        }\n\n        //if I was able to reach this point ... every other CtrlMsg will be notified\n        // send the working directory....\n        GUIMessage m = new GUIMessage(0, new Object[]{getWorkingDirectory(), canWrite});\n        sendMsgImpl(m);\n        // send the user home\n        m = new GUIMessage(1, getUserHome());\n        sendMsgImpl(m);\n        // send the os name\n        m = new GUIMessage(2, getOSName());\n        sendMsgImpl(m);\n        // send the file separator\n        m = new GUIMessage(10, getFileSeparator());\n        sendMsgImpl(m);\n        // send isRoot\n        m = new GUIMessage(5, Boolean.valueOf(isRoot()));\n        sendMsgImpl(m);\n        // send free space\n        m = new GUIMessage(12, freeSpace());\n        sendMsgImpl(m);\n        // send the list of current files\n        m = new GUIMessage(3, getFileList());\n        sendMsgImpl(m);\n        // send the list of roots\n        m = new GUIMessage(4, getRoots());\n        sendMsgImpl(m);\n        // send the list of short names\n        m = new GUIMessage(9, formShortNames());\n        sendMsgImpl(m);\n        // send done init\n        m = new GUIMessage(11, \"Init\");\n        sendMsgImpl(m);\n    }\n\n    private final HashMap<String, String> formShortNames() {\n        h.clear();\n        String roots[] = getRoots();\n        if (roots == null) return h;\n        for (int i = 0; i < roots.length; i++) {\n            h.put(roots[i], getShortRootName(roots[i]));\n        }\n        return h;\n    }\n\n    private final String freeSpace() {\n        if (currentFile == null) return null;\n        try {\n            long space = currentFile.getFreeSpace();\n            return parseSize(space);\n        } catch (Throwable t) {\n        }\n        return null;\n    }\n\n    private final String parseSize(long space) {\n        if (space > 1024l) {\n            space = space / 1024l;\n            if (space > 1024l) {\n                space = space / 1024l;\n                if (space > 1024l) {\n                    space = space / 1024l;\n                    if (space > 1024l) {\n                        space = space / 1024l;\n                        return space + \" TB\";\n                    } else\n                        return space + \" GB\";\n                } else\n                    return space + \" MB\";\n            } else\n                return space + \"KB\";\n        } else {\n            return space + \" B\";\n        }\n    }\n\n    private void cleanup() {\n        if (ois != null) {\n            try {\n                ois.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            ois = null;\n        }\n\n        if (oos != null) {\n            try {\n                oos.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            oos = null;\n        }\n\n        if (controlSocket != null) {\n            try {\n                controlSocket.close();\n            } catch (Throwable t) {\n                //ignore\n            }\n            controlSocket = null;\n        }\n    }\n\n    public void sendCtrlMessage(Object ctrlMsg) throws IOException, FDTProcolException {\n        if (isClosed()) {\n            throw new FDTProcolException(\"Control channel already closed\");\n        }\n\n        if (logger.isLoggable(Level.FINER)) {\n            logger.log(Level.FINER, \"CtrlChannel Queuing for send: \" + ctrlMsg.toString());\n        }\n        qToSend.add(ctrlMsg);\n    }\n\n    private void sendAllMsgs() throws Exception {\n        for (; ; ) {\n            Object ctrlMsg = qToSend.poll();\n            if (ctrlMsg == null) break;\n            sendMsgImpl(ctrlMsg);\n        }\n    }\n\n    private void sendMsgImpl(Object o) throws Exception {\n        try {\n            oos.writeObject(o);\n            oos.reset();//DO NOT CACHE!\n            oos.flush();\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception sending ctrl message\", t);\n            close(\"Exception sending control data\", t);\n            throw new IOException(\" Cannot send ctrl message ( \" + t.getCause() + \" ) \");\n        }\n    }\n\n    public void run() {\n        try {\n            while (!isClosed()) {\n                try {\n                    sendAllMsgs();\n                    Object o = ois.readObject();\n                    if (o == null) continue;\n                    process(o);\n                } catch (SocketTimeoutException ste) {\n                    //ignore this??? or shall I close it() ?\n                } catch (FDTProcolException fdte) {\n                    close(\"FDTProtocolException\", fdte);\n                }\n            }\n\n        } catch (Throwable t) {\n            close(null, t);\n        }\n        close(downMessage(), downCause());\n    }\n\n    protected void internalClose() {\n        try {\n            cleanup();\n        } catch (Throwable ignore) {\n        }\n    }\n\n\n} // end of class ServerSessionManager\n\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/internal/FDTSelectionKey.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport.internal;\n\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.transport.FDTKeyAttachement;\nimport lia.util.net.copy.transport.internal.SelectionManager.SelectionTask;\n\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.UUID;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * This class is used in conjunction with SelectionManager to handle the NIO event readiness It is a wrapper over\n * {@link SelectionKey} with\n *\n * @author ramiro\n */\npublic class FDTSelectionKey {\n\n    private static final SelectionManager selectionManager = SelectionManager.getInstance();\n\n    protected final Selector selector;\n\n    protected final SelectionTask selectionTask;\n\n    protected final SocketChannel channel;\n    protected final UUID fdtSessionID;\n    final SelectionHandler handler;\n\n    final int interests;\n\n    final AtomicBoolean canceled;\n\n    final AtomicBoolean registered;\n\n    final AtomicBoolean renewed;\n    public int opCount;\n    volatile SelectionKey selectionKey;\n    int MSS = -1;\n    private volatile FDTKeyAttachement attachment;\n\n    FDTSelectionKey(UUID fdtSessionID, SocketChannel channel, int interests, SelectionHandler handler, FDTKeyAttachement attachement, Selector selector, SelectionTask selectionTask) {\n        this.channel = channel;\n        this.interests = interests;\n        this.handler = handler;\n\n        renewed = new AtomicBoolean(false);\n        canceled = new AtomicBoolean(false);\n        registered = new AtomicBoolean(false);\n\n        this.fdtSessionID = fdtSessionID;\n        this.attachment = attachement;\n        this.selector = selector;\n        this.selectionTask = selectionTask;\n    }\n\n    public FDTSelectionKey(UUID fdtSessionID, SocketChannel channel, int interests, SelectionHandler handler, FDTKeyAttachement attachement, Selector selector) {\n        this(fdtSessionID, channel, interests, handler, null, selector, null);\n    }\n\n    public FDTSelectionKey(UUID fdtSessionID, SocketChannel channel, int interests, SelectionHandler handler, Selector selector) {\n        this(fdtSessionID, channel, interests, handler, null, selector);\n    }\n\n    public boolean registerInterest() {\n\n        if (registered.compareAndSet(false, true)) {\n            selectionManager.initialKeyRegister(this);\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Should be called to renew the this interest for I/O readiness\n     *\n     * @return true, if the renewal was successful ( if the key is already registered if will remain register and this\n     * function will return false)\n     */\n    public boolean renewInterest() {\n\n        if (renewed.compareAndSet(false, true)) {\n            opCount = 0;\n            selectionManager.renewInterest(this);\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Cancels the I/O readiness interests. It can be called multiple times.\n     *\n     * @return true, only the first time when it is called, and false for any other subsequent calls\n     */\n    public boolean cancel() {\n        if (canceled.compareAndSet(false, true)) {\n            try {\n                this.channel.close();\n            } catch (Throwable t) {\n            }\n\n            if (handler != null) {\n                try {\n                    handler.canceled(this);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n\n            // Is it even possible ... only if the registration failed in the first place !!\n            final SelectionKey selectionKey = this.selectionKey;\n            if (selectionKey != null) {\n                try {\n                    selectionKey.cancel();\n                } catch (Throwable t) {\n                }\n\n                try {\n                    if (selectionKey.selector() != null) {\n                        //just for cleanup - otherwise stalled sockets\n                        renewInterest();\n                    }\n                } catch (Throwable t) {\n                }\n            }\n\n            final FDTKeyAttachement attach = attachment();\n            if (attach != null) {\n                try {\n                    attach.recycleBuffers();\n                } catch (Throwable t) {\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n\n    public boolean isValid() {\n        return !canceled.get();\n    }\n\n    public SocketChannel channel() {\n        return channel;\n    }\n\n    /**\n     * Same functionality provided by NIO's SelectionKey\n     *\n     * @param attachement\n     */\n    public final FDTKeyAttachement attach(FDTKeyAttachement attachement) {\n        FDTKeyAttachement ret = this.attachment;\n        this.attachment = attachement;\n        return ret;\n    }\n\n    public UUID fdtSessionID() {\n        return fdtSessionID;\n    }\n\n    /**\n     * Same functionality provided by NIO's SelectionKey\n     *\n     */\n    public final FDTKeyAttachement attachment() {\n        return attachment;\n    }\n\n    public int getMSS() {\n        return MSS;\n    }\n\n    public void setMSS(int MSS) {\n        this.MSS = MSS;\n    }\n\n    public Selector selector() {\n        return selector;\n    }\n\n    public String toString() {\n        return Utils.toStringSelectionKey(this);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/internal/SelectionHandler.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport.internal;\n\n\n/**\n * Every class interested in I/O Events should implement this.\n * It is used by the SelectionManager to notify I/O readiness\n *\n * @author ramiro\n */\npublic interface SelectionHandler {\n\n    public void handleSelection(FDTSelectionKey fdtSelectionKey);\n\n    public void canceled(FDTSelectionKey fdtSelectionKey);\n\n}\n"
  },
  {
    "path": "src/lia/util/net/copy/transport/internal/SelectionManager.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.copy.transport.internal;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\nimport lia.util.net.copy.transport.FDTKeyAttachement;\n\nimport java.io.IOException;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * Wrapper class for NIO Selector-s and SocketChannel-s, hopefully optimizes the selection process for the entire app.\n * Every select() runs in its own Task. The synchronization should be \"loose\" enough ( a sync per Task ), and probably\n * the contention of selector.wakeup() also. Having queues for FDTKey should scale at high load-s\n *\n * @author ramiro\n */\npublic class SelectionManager {\n\n    private static final Logger logger = Logger.getLogger(SelectionManager.class.getName());\n    // the one and only. Now, go outside and play\n    private static final SelectionManager _thisInstance;\n\n    static {\n        SelectionManager tmpSMgr = null;\n\n        try {\n            tmpSMgr = new SelectionManager();\n            int i = 0;\n            for (Map.Entry<Selector, SelectionTask> entry : tmpSMgr.selTasksMap.entrySet()) {\n                Thread t = new Thread(entry.getValue(), \" [ SelectionManager ] Selection task ( \" + i++ + \" )\");\n                t.setDaemon(true);\n                t.start();\n            }\n        } catch (Throwable t) {\n            logger.log(Level.WARNING, \"Got exception initializing SelectionManager. Cannot continue. Will stop\", t);\n            throw new RuntimeException(\"Cannot instantiate SelectionManager. Do you want to continue ( N/N )? \", t);\n        }\n\n        _thisInstance = tmpSMgr;\n    }\n\n    final Map<Selector, SelectionTask> selTasksMap;\n\n    private final BlockingQueue<Selector> selectorsQueue;\n\n    private SelectionManager() throws IOException {\n        selTasksMap = new HashMap<Selector, SelectionTask>();\n        int sNo = Config.getInstance().getNumberOfSelectors();\n\n        selectorsQueue = new ArrayBlockingQueue<Selector>(sNo);\n        for (int i = 0; i < sNo; i++) {\n            Selector sel = Selector.open();\n            selectorsQueue.add(sel);\n            SelectionTask st = new SelectionTask(sel);\n            selTasksMap.put(sel, st);\n        }\n    }\n\n    public static final SelectionManager getInstance() {\n        return _thisInstance;\n    }\n\n    void renewInterest(FDTSelectionKey fdtSelectionKey) {\n        final SelectionTask st = fdtSelectionKey.selectionTask;\n        boolean bShouldWakeup = false;\n\n        // final ReentrantLock lock = st.lock;\n        // lock.lock();\n        // try {\n        // } finally {\n        // lock.unlock();\n        // }\n        synchronized (st) {\n            if (st.renewQueue.isEmpty() && st.newQueue.isEmpty()) {\n                bShouldWakeup = true;\n            }\n\n            st.renewQueue.add(fdtSelectionKey);\n        }\n\n        if (bShouldWakeup) {\n            st.selector.wakeup();\n        }\n    }\n\n    /**\n     * This should not be used from FDT ....\n     *\n     * @param channel\n     * @param interests\n     * @param selectionHandler\n     * @return\n     * @throws InterruptedException\n     * @throws IOException\n     */\n    public FDTSelectionKey register(final SocketChannel channel, final int interests, final SelectionHandler selectionHandler) throws InterruptedException, IOException {\n        return register(null, channel, interests, selectionHandler);\n    }\n\n    /**\n     * This method register a channel with specific interests. The readiness will be notified to\n     * <code>SelectionHandler</code> parameter If this key is canceled during the selection process ( e.g stream closes\n     * ) the same handler will be notified\n     *\n     * @param fdtsessionID\n     * @param channel\n     * @param interests\n     * @param selectionHandler\n     * @return\n     * @throws InterruptedException\n     * @throws IOException\n     */\n    public FDTSelectionKey register(final UUID fdtsessionID, final SocketChannel channel, final int interests, final SelectionHandler selectionHandler) throws InterruptedException {\n        return register(fdtsessionID, channel, interests, selectionHandler, null);\n    }\n\n    // TODO ... extra checks to see if a channel is already registered\n    public FDTSelectionKey register(final UUID fdtsessionID, final SocketChannel channel, final int interests, final SelectionHandler selectionHandler, final FDTKeyAttachement attach) throws InterruptedException {\n\n        if (channel == null) {\n            throw new NullPointerException(\"SocketChannel cannot be null\");\n        }\n\n        if (selectionHandler == null) {\n            throw new NullPointerException(\"SelectionHanfler cannot be null\");\n        }\n\n        final Selector sel = getAndRotateSelector();\n        final SelectionTask sTask = selTasksMap.get(sel);\n\n        FDTSelectionKey fdtSelectionKey = new FDTSelectionKey(fdtsessionID, channel, interests, selectionHandler, attach, sel, sTask);\n\n        return fdtSelectionKey;\n    }\n\n    public void stopIt() {\n        try {\n            for (Map.Entry<Selector, SelectionTask> entry : selTasksMap.entrySet()) {\n                entry.getValue().stopIt();\n                entry.getValue().selector.wakeup();\n            }\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n    }\n\n    void initialKeyRegister(FDTSelectionKey fdtSelectionKey) {\n\n        final Selector sel = fdtSelectionKey.selector;\n        final SelectionTask st = fdtSelectionKey.selectionTask;\n\n        boolean bShouldWakeup = false;\n\n        // something gone wrong if either the Selector or the SelectionTask are\n        // null\n\n        // final ReentrantLock lock = st.lock;\n\n        // lock.lock();\n        // try {\n        // } finally {\n        // lock.unlock();\n        // }\n\n        synchronized (st) {\n            if (st.renewQueue.isEmpty() && st.newQueue.isEmpty()) {\n                bShouldWakeup = true;\n            }\n\n            st.newQueue.add(fdtSelectionKey);\n        }\n\n        if (bShouldWakeup) {\n            sel.wakeup();\n        }\n    }\n\n    // just serve them in round robin stile\n    private Selector getAndRotateSelector() throws InterruptedException {\n        final Selector sel = selectorsQueue.take();\n        selectorsQueue.put(sel);\n        return sel;\n    }\n\n    // should be one for every Selector - handles the selection process\n    final static class SelectionTask implements Runnable {\n\n        private final Selector selector;\n\n        private final AtomicBoolean hasToRun;\n\n        // this lock guards the (re)new queues\n        // performance is a moving target :); synchronized in better in Java6 ( AQS ;) )\n        // private final ReentrantLock lock = new ReentrantLock();\n\n        private final Deque<FDTSelectionKey> renewQueue;\n\n        private final Deque<FDTSelectionKey> newQueue;\n\n        SelectionTask(Selector selector) {\n\n            renewQueue = new ArrayDeque<FDTSelectionKey>();\n            newQueue = new ArrayDeque<FDTSelectionKey>();\n\n            hasToRun = new AtomicBoolean(false);\n\n            if (selector == null) {\n                throw new NullPointerException(\"Selector cannot be null in SelectionTask constructor\");\n            }\n\n            if (!selector.isOpen()) {\n                throw new IllegalArgumentException(\"Selector is not open in SelectionTask constructor\");\n            }\n\n            this.selector = selector;\n            hasToRun.set(true);\n        }\n\n        private void checkRenew() {\n            final Queue<FDTSelectionKey> l = renewQueue;\n\n            if (l.isEmpty())\n                return;\n\n            final boolean finest = logger.isLoggable(Level.FINEST);\n            // the lock must be taken already\n            while (!l.isEmpty()) {\n                final FDTSelectionKey fdtSelectionKey = l.remove();\n                if (finest) {\n                    StringBuilder sb = new StringBuilder();\n                    sb.append(\"[ SelectionManager ] [ checkRenew ] for \").append(Utils.toStringSelectionKey(fdtSelectionKey));\n                    logger.log(Level.FINEST, sb.toString());\n                }\n\n                final SelectionKey sk = fdtSelectionKey.selectionKey;\n\n                if (!sk.isValid()) {\n                    fdtSelectionKey.cancel();\n                    continue;\n                }\n\n                sk.interestOps(fdtSelectionKey.selectionKey.interestOps() | fdtSelectionKey.interests);\n            }\n        }\n\n        private void checkNew() {\n            final Queue<FDTSelectionKey> l = newQueue;\n            // speed-up things a little bit\n            if (l.isEmpty())\n                return;\n\n            final boolean finest = logger.isLoggable(Level.FINEST);\n            // the lock must be taken already\n            while (!l.isEmpty()) {\n                try {\n                    final FDTSelectionKey fdtSelectionKey = l.remove();\n                    fdtSelectionKey.selectionKey = fdtSelectionKey.channel.register(selector, fdtSelectionKey.interests, fdtSelectionKey);\n                    if (finest) {\n                        StringBuilder sb = new StringBuilder();\n                        sb.append(\"[ SelectionManager ] [ checkNew ] for \").append(Utils.toStringSelectionKey(fdtSelectionKey));\n                        logger.log(Level.FINEST, sb.toString());\n                    }\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" [ SelectionManager ] [ checkNew ] got exception. Cause\", t);\n                }\n            }\n\n        }\n\n        public void run() {\n\n            int count = 0;\n\n            // final ReentrantLock lock = this.lock;\n            // final Object lock = this;\n\n            while (hasToRun.get()) {\n\n                synchronized (this) {\n                    checkRenew();\n                    checkNew();\n                }\n                // try {\n                // } finally {\n                // lock.unlock();\n                // }\n\n                try {\n                    count = selector.select();\n                } catch (IOException ioe) {\n                    logger.log(Level.WARNING, \" [ SelectionManager ] [ SelectionTask ] IOException in selector.select(). Cause: \", ioe);\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \" [ SelectionManager ] [ SelectionTask ] Generic Exception in selector.select(). Cause: \", t);\n                }\n\n                // maybe a renew ...\n                if (count == 0)\n                    continue;\n\n                final Iterator<SelectionKey> it = selector.selectedKeys().iterator();\n                while (it.hasNext()) {\n\n                    final SelectionKey sk = it.next();\n                    try {\n                        it.remove();\n\n                        final FDTSelectionKey fdtSelectionKey = (FDTSelectionKey) sk.attachment();\n\n                        if (!sk.isValid()) {\n                            if (fdtSelectionKey != null) {\n                                fdtSelectionKey.cancel();\n                            }\n                            continue;\n                        }\n\n                        if (fdtSelectionKey != null) {\n\n                            // cancel the interest\n                            // TODO - This works for single registration keys (\n                            // it does not work if fdtSelectionKey.interests ==\n                            // OP_READ | OP_WRITE )\n\n                            sk.interestOps(sk.interestOps() & ~fdtSelectionKey.interests);\n                            fdtSelectionKey.renewed.set(false);\n                            fdtSelectionKey.handler.handleSelection(fdtSelectionKey);\n                        } else {\n                            logger.log(Level.WARNING, \"\\n\\n fdtSelectionKey is null in selection loop for sk: \" + sk + \" channel: \" + sk.channel() + \". The channle will be closed\\n\\n\");\n                            sk.cancel();\n                            try {\n                                sk.channel().close();\n                            } catch (Throwable ignore) {\n                            }\n                        }\n                    } catch (Throwable t) {\n                        logger.log(Level.WARNING, \" [ SelectionManager ] [ SelectionTask ] Exception in main loop notifying FDTKeys to handlers. Cause: \", t);\n                    }\n                }// while - iterator\n\n            }// while - hasToRun\n\n            cancelAllKeys();\n        }\n\n        private void cancelAllKeys() {\n            SelectionKey sk = null;\n            FDTSelectionKey fsk = null;\n            for (Iterator<SelectionKey> it = selector.keys().iterator(); it.hasNext(); ) {\n                try {\n                    sk = it.next();\n\n                    if (sk != null) {\n                        fsk = (FDTSelectionKey) sk.attachment();\n                        if (fsk != null) {\n                            fsk.cancel();\n                        }\n                    }\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }// for()\n        }\n\n        public void stopIt() {\n            if (hasToRun.compareAndSet(true, false)) {\n                selector.wakeup();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/lia/util/net/jiperf/ByteBufferPool.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf;\n\nimport java.nio.ByteBuffer;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.TimeUnit;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic class ByteBufferPool {\n\n    //TODO - dynamicaly set this size\n    public static final int BUFFER_SIZE = 32 * 1024 * 1024;//32 MBytes\n    //TODO - the size will have to be set based on the capacity() of the\n    //current buffers in the pool\n    //For the momnet it will be the size of the \"list\" of the buffers - should be a long instead of an integer\n    public static final int POOL_SIZE = 10;\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(ByteBufferPool.class.getName());\n    //the list of ByteBuffer-s\n    public static ByteBufferPool _theInstance;\n\n    //used for double checked locking\n    private static volatile boolean initialized = false;\n\n    ArrayBlockingQueue<ByteBuffer> thePool;\n\n    private ByteBufferPool() {\n        thePool = new ArrayBlockingQueue<ByteBuffer>(POOL_SIZE);\n\n        int i = 0;\n        for (i = 0; i < POOL_SIZE; i++) {\n            try {\n                if (!thePool.offer(ByteBuffer.allocateDirect(BUFFER_SIZE))) {\n                    logger.log(Level.WARNING, \" Queue full ??? Should not happen ...\");\n                }\n            } catch (OutOfMemoryError oom) {\n                logger.log(Level.WARNING, \" Please try to increase -XX:MaxDirectMemorySize=256m \", oom);\n                break;\n            } catch (Throwable t) {\n                logger.log(Level.WARNING, \" Got general exception trying to allocate the mem\", t);\n                break;\n            }\n        }\n\n        logger.log(Level.INFO, \" Succesfully alocated \" + i + \" buffers\");\n    }\n\n    public static final ByteBufferPool getInstance() {\n\n        //double checked locking\n        if (!initialized) {\n            synchronized (ByteBufferPool.class) {\n                if (!initialized) {\n                    _theInstance = new ByteBufferPool();\n                }\n            }\n        }\n\n        return _theInstance;\n    }\n\n    public ByteBuffer get() {\n        ByteBuffer retBuff = null;\n\n        while (retBuff == null) {\n            try {\n                retBuff = thePool.poll(10, TimeUnit.SECONDS);\n            } catch (InterruptedException ie) {\n                logger.log(Level.WARNING, \" The thread was interrupted trying to get a buffer from the pool\", ie);\n            }\n            if (retBuff == null) {\n                logger.log(Level.WARNING, \" Timeot reached ... unable to get a buffer. You should increase the pool size\");\n            }\n        }\n\n        return retBuff;\n    }\n\n    public void put(ByteBuffer buff) {\n\n        //TODO - extra checks here\n        buff.clear();\n        thePool.offer(buff);\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/jiperf/JIperf.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf;\n\nimport java.util.HashMap;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.logging.Logger;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic class JIperf {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(JIperf.class.getName());\n\n    /**\n     * The executor used to perform I/O tasks\n     */\n    private static final ExecutorService executor;\n\n    static {\n        ThreadPoolExecutor texecutor = new ThreadPoolExecutor(5, 20, 2 * 60, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadFactory() {\n            AtomicLong l = new AtomicLong(0);\n\n            public Thread newThread(Runnable r) {\n                return new Thread(r, \" JIperf Worker Task \" + l.getAndIncrement());\n            }\n        });\n        texecutor.setRejectedExecutionHandler(new RejectedExecutionHandler() {\n            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {\n                try {\n                    // slow down a little bit\n                    final long SLEEP_TIME = Math.round(Math.random() * 1000D + 1);\n                    try {\n                        Thread.sleep(SLEEP_TIME);\n                    } catch (Throwable ignore) {\n                    }\n                    System.err.println(\"\\n\\n [ RejectedExecutionHandler ] slept for \" + SLEEP_TIME);\n                    // resubmit the task!\n                    executor.execute(r);\n                } catch (Throwable t) {\n                    t.printStackTrace();\n                }\n            }\n        });\n\n        // it will be added in 1.6\n        // texecutor.allowCoreThreadTimeOut(true);\n        texecutor.prestartAllCoreThreads();\n        executor = texecutor;\n    }\n\n    public static final ExecutorService getExecutor() {\n        return executor;\n    }\n\n    public static final void shutdownExecutor() {\n        executor.shutdown();\n        try {\n            if (!executor.awaitTermination(10L, TimeUnit.SECONDS))\n                executor.shutdownNow();\n        } catch (Exception e) {\n            //nothing to do\n        }\n    }\n\n    private static HashMap<String, String> parseArguments(final String args[]) {\n        if (args == null || args.length == 0)\n            return null;\n        HashMap<String, String> rHM = new HashMap<String, String>();\n\n        for (int i = 0; i < args.length - 1; i++) {\n            if (args[i].startsWith(\"-\")) {\n                if (args[i + 1].startsWith(\"-\")) {\n                    rHM.put(args[i], \"\");\n                } else {\n                    rHM.put(args[i], args[i + 1]);\n                    i++;\n                }\n            }\n        }\n        if (args[args.length - 1].startsWith(\"-\"))\n            rHM.put(args[args.length - 1], \"\");\n\n        return rHM;\n    }\n\n    public static void printHelp() {\n        System.err.println(\"Usage:\");\n        System.err.println(\"\\tServer\");\n        System.err.println(\"\\t\\tstandalone: java JIperf -s -p portNumer -P numberOfThreads -w windowSize\");\n        System.err.println(\"\\t\\tUse a SSH control connection: java JIperf -s -ssh\");\n        System.err.println(\"\\tClient\");\n        System.err.println(\"\\t\\tstandalone: java JIperf -c host -p portNumer -P numberOfThreads -w windowSize\");\n        System.err.println(\"\\t\\tremotely start a jiperf server: java JIperf -c host -ssh [-u user] [-E command] -p portNumer -P numberOfThreads -w windowSize\");\n\n    }\n\n    public static void main(String[] args) {\n        try {\n            HashMap<String, String> argsMap = parseArguments(args);\n            if (argsMap.containsKey(\"-c\")) {\n                JIperfClient client = new JIperfClient(argsMap);\n                client.flood();\n            } else if (argsMap.containsKey(\"-s\")) {\n                JIperfServer server = new JIperfServer(argsMap);\n                server.doWork();\n\n            } else {\n                printHelp();\n                System.exit(0);\n            }\n        } catch (Throwable t) {\n            t.printStackTrace();\n            System.exit(1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/lia/util/net/jiperf/JIperfClient.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf;\n\nimport lia.util.net.jiperf.control.ControlStream;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.SocketChannel;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.Executor;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic class JIperfClient {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(JIperfClient.class.getName());\n\n    Selector sel;\n\n    int serverPort;\n\n    int sockNum;\n\n    String serverHost;\n\n    Executor executor;\n\n    ByteBufferPool buffPool;\n\n    // this should be the \"staging\" queue ... should be a \"self-adjusting\" buffer\n    ArrayBlockingQueue<ByteBuffer> queueToSend;\n\n    //SSH control stream\n    private ControlStream control;\n\n    public JIperfClient(final HashMap<String, String> config) throws Exception {\n        serverPort = Integer.parseInt(config.get(\"-p\"));\n        serverHost = config.get(\"-c\");\n\n        try {\n            sockNum = Integer.parseInt(config.get(\"-P\"));\n        } catch (Throwable t) {\n            sockNum = 1;\n        }\n\n        /** --SSH mode-- */\n\t\t/* we start the remote jiperf server */\n        if (config.containsKey(\"-ssh\")) {\n            String user;\n            if (config.containsKey(\"-u\"))\n                user = config.get(\"-u\");\n            else\n                user = System.getProperty(\"user.name\");\n            String command;\n            if (config.containsKey(\"-E\"))\n                command = config.get(\"-E\");\n            else //TODO, maybe set the default the default command to a more generic path\n                command = \"java -XX:MaxDirectMemorySize=512m -cp ~/JIPERF/TEST_JAVA_IO_PERF/JPERF_NIO/bin lia.util.net.jiperf.JIperf -ssh -s\";\n            System.out.println(\" [Client] Using SSH mode: connecting to \" + user + \"@\" + serverHost + \" start command:\" + command);\n            try {\n                control = new ControlStream();\n                control.startServer(serverHost, user, command);\n                control.waitAck();\n                //if NAT is in place, the user may specify the gateway IP to be allowed in JIPerf server\n                String myIP = null;\n                if (config.containsKey(\"-F\"))\n                    myIP = config.get(\"-F\");\n                control.sendInitCommands(myIP, serverPort, sockNum, -1);\n                control.waitAck();\n            } catch (Exception e) {\n                System.out.println(\" [Client] ERROR: \" + e);\n                System.exit(1);\n            }\n        }\n        /** --SSH mode-- */\n\n        // TODO - the size should also dynamically ajust .... depends very much on the performance\n        // of the \"filling\" threads ;)\n        queueToSend = new ArrayBlockingQueue<ByteBuffer>(ByteBufferPool.POOL_SIZE + 1);\n        buffPool = ByteBufferPool.getInstance();\n\n        if (sockNum < 1)\n            sockNum = 1;\n        init();\n        executor = JIperf.getExecutor();\n\n    }\n\n    public void init() throws Exception {\n\n        sel = Selector.open();\n\n        InetSocketAddress addr = new InetSocketAddress(serverHost, serverPort);\n        for (int i = 0; i < sockNum; i++) {\n            SocketChannel sc = SocketChannel.open();\n\n            sc.configureBlocking(false);\n\n            System.out.println(\"initiating connection\");\n\n            sc.connect(addr);\n\n            // TODO ... for the moment there is a 1-1 mapping between \"filling threads\" and number of sockets ...\n            Thread t = new Thread(new FillingTask());\n            t.setDaemon(true);\n            t.start();\n\n            while (!sc.finishConnect()) {\n                // TODO - do something useful\n                try {\n                    Thread.sleep(100);\n                } catch (Exception ex) {\n                }\n                ;\n            }\n\n            System.out.println(\"connection established\");\n            sc.register(sel, SelectionKey.OP_WRITE);\n        }\n\n    }\n\n    public void flood() throws Exception {\n        for (; ; ) {\n            while (sel.select() > 0)\n                ;\n\n            Iterator it = sel.selectedKeys().iterator();\n            while (it.hasNext()) {\n                SelectionKey sk = (SelectionKey) it.next();\n\n                if (sk.isWritable()) {\n                    sk.interestOps(sk.interestOps() & ~SelectionKey.OP_WRITE);\n                    executor.execute(new WriterTask(sk));\n                }\n\n                it.remove();\n            }\n        }\n\n    }\n\n    class FillingTask implements Runnable {\n\n        FileChannel readChannel;\n\n        FillingTask() throws Exception {\n            File dev_zero = new File(\"/dev/zero\");\n            readChannel = new FileInputStream(dev_zero).getChannel();\n        }\n\n        public void run() {\n            for (; ; ) {\n                try {\n                    ByteBuffer buff = buffPool.get();\n\n                    readChannel.read(buff);// TODO - should check if it read buff.size()\n                    buff.flip();\n                    queueToSend.put(buff);\n\n                } catch (Throwable t) {\n                    logger.log(Level.WARNING, \"Filling task got exc\", t);\n                    try {\n                        Thread.sleep(50);\n                    } catch (Throwable t1) {\n                    }\n                }\n            }\n        }\n    }\n\n    class WriterTask implements Runnable {\n\n        SelectionKey sk;\n\n        ByteBuffer buff;\n\n        WriterTask(SelectionKey sk) {\n            this.sk = sk;\n            // take a free buffer from the pool\n        }\n\n        private void writeData() throws Exception {\n            buff = queueToSend.take();\n            SocketChannel sc = (SocketChannel) sk.channel();\n            int count = -1;\n            while ((count = sc.write(buff)) > 0)\n                ;\n\n            // TODO - here we should check for buff.remainig() !!!!\n            if (count < 0) {\n                sc.close();\n            } else {\n                sk.interestOps(sk.interestOps() | SelectionKey.OP_WRITE);\n            }\n\n            sel.wakeup();\n\n        }// readData()\n\n        public void run() {\n            if (sk == null)\n                return;\n            try {\n                writeData();\n                /*try { disable flooding\n\t\t\t\t\tThread.sleep(1000);\n\t\t\t\t} catch (Throwable t1) {\n\t\t\t\t}*/\n            } catch (Throwable t) {\n                t.printStackTrace();\n            } finally {\n                // *ALWAYS* return the buffer to the pool whatever happens\n                buffPool.put(buff);\n            }\n        }\n    }// WriterTask class\n}\n"
  },
  {
    "path": "src/lia/util/net/jiperf/JIperfServer.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf;\n\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.SelectionKey;\nimport java.nio.channels.Selector;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.concurrent.ExecutorService;\nimport java.util.logging.Logger;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic class JIperfServer {\n\n    /**\n     * Logger used by this class\n     */\n    private static final transient Logger logger = Logger.getLogger(JIperfServer.class.getName());\n\n    ServerSocketChannel ssc;\n\n    ServerSocket ss;\n\n    Selector sel;\n\n    int port;\n\n    ByteBufferPool buffPool;\n\n    ExecutorService executor;\n\n    /**\n     * -- SSH Mode fields --\n     */\n    boolean sshMode = false;\n\n    /**\n     * the Client/Gateway IP that this server restricts connections from if not set, the connections will not be checked against this\n     */\n    String allowedIP = null;\n\n    /**\n     * the number of connection that the server accept from the allowedIP\n     */\n    int connectionNo;\n\n    /**\n     * window size on client side (server should consider this when accepting connections?)\n     */\n    int windowSize;\n\n    public JIperfServer(final HashMap<String, String> config) throws Exception {\n        /** --SSH mode-- */\n        /* we start the remote jiperf server */\n        if (config.containsKey(\"-ssh\")) {\n            sshMode = true;\n            initSSH();\n        } else {\n            port = Integer.parseInt(config.get(\"-p\"));\n            init();\n        }\n    }\n\n    private void init() throws Exception {\n        buffPool = ByteBufferPool.getInstance();\n        executor = JIperf.getExecutor();\n\n        ssc = ServerSocketChannel.open();\n        ssc.configureBlocking(false);\n\n        ss = ssc.socket();\n        ss.bind(new InetSocketAddress(port));\n\n        sel = Selector.open();\n        ssc.register(sel, SelectionKey.OP_ACCEPT);\n    }\n\n    private void initSSH() throws Exception {\n        // stdin,stdout are tunneled through SSH and used as control in/out streams\n        java.io.BufferedReader stdin = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));\n        try {\n            System.out.println(\"ACK1\");\n            allowedIP = stdin.readLine();\n            port = Integer.parseInt(stdin.readLine());\n            connectionNo = Integer.parseInt(stdin.readLine());\n            windowSize = Integer.parseInt(stdin.readLine());\n            System.err.println(\"Conection parameters received: IP: \" + allowedIP + \" PORT: \" + port + \" STREAMS: \" + connectionNo + \" WSIZE: \" + windowSize);\n            init();\n            System.out.println(\"ACK2\");\n        } catch (Throwable t) {\n            System.err.println(\"Invalid connection parameters\" + t.getMessage());\n            ssc.close();\n            ss.close();\n            System.exit(1);\n        }\n        /** --SSH mode-- */\n    }\n\n    public void doWork() throws Exception {\n        for (; ; ) {\n            //TODO, stop the server (this loop and the executor) if there are no more connected sockets\n            while (sel.select() > 0)\n                ;\n            Iterator it = sel.selectedKeys().iterator();\n            while (it.hasNext()) {\n                SelectionKey sk = (SelectionKey) it.next();\n\n                if (sk.isAcceptable()) {\n                    ServerSocketChannel ssc = (ServerSocketChannel) sk.channel();\n                    SocketChannel sc = ssc.accept();\n                    if (!sshMode) {// standalone mode\n                        sc.configureBlocking(false);\n                        sc.register(sel, SelectionKey.OP_READ);\n                    } else {// SSH mode\n                        if (allowedIP != null && !allowedIP.equals(sc.socket().getInetAddress().getHostAddress())) {\n                            // just the IP passed on secured SSH control connection is allowed to connect\n                            System.err.println(\" [\" + allowedIP + \"] does not match \" + sc.socket().getInetAddress().getHostAddress());\n                            sc.close();\n                        } else {// allowed connection\n                            sc.configureBlocking(false);\n                            sc.register(sel, SelectionKey.OP_READ);\n                            if (--connectionNo == 0) {\n                                // stop listening for other connection\n                                this.ssc.keyFor(sel).cancel();\n                                this.ssc.close();\n                            }\n                        }\n                    }\n                } else if (sk.isReadable()) {\n                    sk.interestOps(sk.interestOps() & ~SelectionKey.OP_READ);\n                    executor.execute(new ReaderTask(sk));\n                }\n\n                it.remove();\n            }\n        }\n\n\n    }\n\n    class ReaderTask implements Runnable {\n\n        SelectionKey sk;\n\n        ByteBuffer buff;\n\n        ReaderTask(SelectionKey sk) {\n            this.sk = sk;\n            // take a free buffer from the pool\n            buff = buffPool.get();\n        }\n\n        private void readData() throws Exception {\n            buff.clear();\n            SocketChannel sc = (SocketChannel) sk.channel();\n            int count = -1;\n            while ((count = sc.read(buff)) > 0) {\n                // TODO - in the future pass this to a \"listener\" which will do something useful with this buffer\n                buff.clear();\n            }\n\n            if (count < 0) {\n                sc.close();\n            } else {\n                sk.interestOps(sk.interestOps() | SelectionKey.OP_READ);\n            }\n\n            sel.wakeup();\n\n        }// readData()\n\n        public void run() {\n            if (sk == null)\n                return;\n            try {\n                readData();\n            } catch (Throwable t) {\n                t.printStackTrace();\n            } finally {\n                // *ALWAYS* return the buffer to the pool whatever happens\n                buffPool.put(buff);\n            }\n        }\n    }// ReaderTask class\n}\n"
  },
  {
    "path": "src/lia/util/net/jiperf/control/ControlStream.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf.control;\n\nimport lia.util.net.common.LocalHost;\n\nimport java.io.*;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic class ControlStream implements StreamConsumer {\n    // consume stderr lines\n\n    public BufferedReader stdout;\n\n    public PrintWriter stdin;\n\n    public Process proc;\n\n    public Thread stderr;\n\n    public static boolean isStdinOpen() {\n        return FileDescriptor.in.valid();\n    }\n\n    public static void main(String[] args) throws IOException {\n        // Execute the command using the specified environment\n        System.out.println(LocalHost.getPublicIP4());\n        ControlStream c = new ControlStream();\n        System.out.println(args[1]);\n        c.startServer(args[0], args[1], args[2]);\n        c.stdin.println(\"LINE\");\n        System.out.println(\" WAIT\");\n        // Parse the stdout of the command\n        String line;\n        StringBuffer buff = new StringBuffer();\n        while ((line = c.stdout.readLine()) != null) {\n            buff.append(line).append('\\n');\n        }\n        String sStdout = buff.toString();\n        // Set the exit code\n        c.awaitTermination();\n        int exitCode = c.proc.exitValue();\n        System.out.println(\"Stdout (\" + exitCode + \"): \" + sStdout);\n    }\n\n    public void consumeLine(String line) {\n        System.err.println(\" [Server] DEBUG:\" + line);\n        // System.exit(1);\n    }\n\n    public void startServer(String host, String username, String command) throws IOException {\n        this.proc = Runtime.getRuntime().exec(\"ssh -l \" + username + \" \" + host + \" \" + command);\n        this.stdout = new BufferedReader(new InputStreamReader(proc.getInputStream()));\n        StreamPumper errorPumper = new StreamPumper(proc.getErrorStream(), null, this);\n        this.stderr = new Thread(errorPumper);\n        this.stderr.start();\n        this.stdin = new PrintWriter(proc.getOutputStream(), true);\n    }\n\n    public void sendInitCommands(String myIp, int port, int threadsNumber, int windowSize) {\n        if (myIp == null || myIp.length() == 0)\n            myIp = LocalHost.getPublicIP4();\n        this.stdin.println(myIp);\n        this.stdin.println(port);\n        this.stdin.println(threadsNumber);\n        this.stdin.println(windowSize);\n    }\n\n    //\t read the ACK from server (blocking the thread)\n    public void waitAck() throws IOException {\n        String sAck = this.stdout.readLine();\n        if (sAck == null) {\n            throw new IOException(\"Invalid ack message\");\n        }\n    }\n\n    public void destroy() {\n        proc.destroy();\n    }\n\n    public void awaitTermination() {\n        try {\n            proc.waitFor();\n            // cleanup\n            stderr.join();\n            proc.getInputStream().close();\n            proc.getOutputStream().close();\n            proc.getErrorStream().close();\n        } catch (Exception e) {\n            System.err.println(\"Thread was interrupted while executing command \\\"\" + \"\\\".\" + e);\n        }\n    }\n}"
  },
  {
    "path": "src/lia/util/net/jiperf/control/StreamConsumer.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf.control;\n\n/**\n * This will be kept for history :).\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\n * started as an Iperf-like test for Java.\n *\n * @author ramiro\n */\npublic interface StreamConsumer {\n    /**\n     * Called when the StreamPumper pumps a line from the Stream.\n     */\n    public void consumeLine(String line);\n}\n\n"
  },
  {
    "path": "src/lia/util/net/jiperf/control/StreamPumper.java",
    "content": "/*\r\n * $Id$\r\n */\r\npackage lia.util.net.jiperf.control;\r\n\r\nimport java.io.*;\r\n\r\n/**\r\n * This will be kept for history :).\r\n * The entire package lia.util.net.jiperf is the very first version of FDT. It\r\n * started as an Iperf-like test for Java.\r\n *\r\n * @author ramiro\r\n */\r\npublic class StreamPumper implements Runnable {\r\n\r\n    private static final int SIZE = 1024;\r\n    private BufferedReader in;\r\n    private StreamConsumer consumer = null;\r\n    private PrintWriter out = new PrintWriter(System.out);\r\n\r\n    public StreamPumper(InputStream in, PrintWriter writer) {\r\n        this(in);\r\n        out = writer;\r\n    }\r\n\r\n    public StreamPumper(InputStream in) {\r\n        this.in = new BufferedReader(new InputStreamReader(in), SIZE);\r\n    }\r\n\r\n    public StreamPumper(InputStream in, StreamConsumer consumer) {\r\n        this(in);\r\n        this.consumer = consumer;\r\n    }\r\n\r\n    public StreamPumper(InputStream in, PrintWriter writer,\r\n                        StreamConsumer consumer) {\r\n        this(in);\r\n        this.out = writer;\r\n        this.consumer = consumer;\r\n    }\r\n\r\n    public void run() {\r\n        try {\r\n            String s = in.readLine();\r\n            while (s != null) {\r\n                consumeLine(s);\r\n                if (out != null) {\r\n                    out.println(s);\r\n                    out.println(\"<DONE>\");\r\n                    out.flush();\r\n                }\r\n\r\n                s = in.readLine();\r\n            }\r\n        } catch (IOException e) {\r\n            // do nothing\r\n        } finally {\r\n            try {\r\n                in.close();\r\n            } catch (IOException e) {\r\n                // do nothing\r\n            }\r\n        }\r\n    }\r\n\r\n    public void flush() {\r\n        out.flush();\r\n    }\r\n\r\n    public void close() {\r\n        flush();\r\n        out.close();\r\n    }\r\n\r\n    private void consumeLine(String line) {\r\n        if (consumer != null) {\r\n            consumer.consumeLine(line);\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "src/lia/util/net/jiperf/test/FDTNetPerf.java",
    "content": "/*\n * $Id$\n */\npackage lia.util.net.jiperf.test;\n\nimport lia.util.net.common.Config;\nimport lia.util.net.common.Utils;\n\nimport java.net.InetAddress;\nimport java.net.InetSocketAddress;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ServerSocketChannel;\nimport java.nio.channels.SocketChannel;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ScheduledThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * The simplest JIperf blocking Client/Server ... used only for testing\n *\n * @author ramiro\n */\npublic class FDTNetPerf {\n\n    private static final ExecutorService execThPool = Utils.getStandardExecService(\"ExecService\", 3, 100, Thread.MAX_PRIORITY);\n    private static final ScheduledThreadPoolExecutor monitorThPool = Utils.getSchedExecService(\"MonitorService\", 1, Thread.MIN_PRIORITY);\n    private static int port = 54320;\n    private static AtomicLong totalBytes = new AtomicLong(0);\n    private static int byteBufferSize = 512 * 1024;\n    private static int buffCount = 1;\n\n    private FDTNetPerf(Map<String, Object> argsMap) throws Exception {\n        monitorThPool.scheduleWithFixedDelay(new FDTNetPerfMonitorTask(), 1, 2, TimeUnit.SECONDS);\n        Object host = argsMap.get(\"-c\");\n        if (host != null) {\n            execThPool.execute(new FDTNetPerfClient(host.toString(), port));\n        } else {\n            execThPool.execute(new FDTNetPerfServer());\n        }\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) {\n        Map<String, Object> argsMap = Utils.parseArguments(args, Config.SINGLE_CMDLINE_ARGS);\n\n        byteBufferSize = Utils.getIntValue(argsMap, \"-bs\", byteBufferSize);\n        buffCount = Utils.getIntValue(argsMap, \"-bn\", buffCount);\n        port = Utils.getIntValue(argsMap, \"-p\", port);\n\n        try {\n            new FDTNetPerf(argsMap);\n        } catch (Throwable t) {\n            t.printStackTrace();\n            System.exit(1);\n        }\n\n        for (; ; ) {\n            try {\n                Thread.sleep(10000000);\n            } catch (Throwable ignore) {\n            }\n        }\n\n    }\n\n    private static class FDTNetPerfServer implements Runnable {\n\n        private ServerSocketChannel ssc;\n\n        FDTNetPerfServer() throws Exception {\n            ssc = ServerSocketChannel.open();\n            ssc.configureBlocking(true);\n\n            ssc.socket().bind(new InetSocketAddress(port));\n        }\n\n        public void run() {\n            try {\n                SocketChannel sc = ssc.accept();\n                sc.configureBlocking(true);\n                execThPool.execute(new FDTNetPerfClient(sc));\n            } catch (Throwable t) {\n                t.printStackTrace();\n            }\n        }\n    }\n\n    private static class FDTNetPerfClient implements Runnable {\n        SocketChannel sc;\n        //        private ByteBuffer buff = ByteBuffer.allocateDirect(8 * 1024 * 1024);\n//        private ByteBuffer buff = ByteBuffer.allocateDirect(512 * 1024);\n        private ByteBuffer[] buffs;\n\n        private boolean shouldWrite;\n\n        private FDTNetPerfClient() throws Exception {\n            int bCount = 0;\n            ArrayList<ByteBuffer> buffsList = new ArrayList<ByteBuffer>(buffCount);\n            try {\n                for (int i = 0; i < buffCount; i++) {\n                    buffsList.add(ByteBuffer.allocateDirect(byteBufferSize));\n                    bCount++;\n                }\n            } catch (OutOfMemoryError oom) {\n                System.out.println(\"Reached OOM while alocating buffers. Allocated \" + bCount + \" buffers\");\n            }\n\n            if (bCount > 0) {\n                buffs = buffsList.toArray(new ByteBuffer[buffsList.size()]);\n                System.out.println(\"buffs.size() = \" + (buffs.length * byteBufferSize) / 1024 + \" KB\");\n            } else {\n                throw new Exception(\"Cannot instantiate the buff pool\");\n            }\n        }\n\n        FDTNetPerfClient(String host, int port) throws Exception {\n            this();\n            this.sc = SocketChannel.open();\n            this.sc.configureBlocking(true);\n            this.sc.socket().connect(new InetSocketAddress(InetAddress.getByName(host), port));\n            shouldWrite = true;\n        }\n\n        FDTNetPerfClient(SocketChannel sc) throws Exception {\n            this();\n            this.sc = sc;\n            shouldWrite = false;\n        }\n\n        public void run() {\n            try {\n                for (; ; ) {\n                    if (shouldWrite) {\n                        for (ByteBuffer buff : buffs) {\n                            buff.position(0);\n                            buff.limit(buff.capacity());\n                        }\n                        totalBytes.addAndGet(sc.write(buffs));\n                    } else {\n                        for (ByteBuffer buff : buffs) {\n                            buff.clear();\n                        }\n                        totalBytes.addAndGet(sc.read(buffs));\n                    }\n                }\n            } catch (Throwable t) {\n                t.printStackTrace();\n            }\n        }\n    }\n\n    private static class FDTNetPerfMonitorTask implements Runnable {\n\n        private long lastCount;\n        private long lastRun;\n\n        public void run() {\n\n            final long currentCount = totalBytes.get();\n            final long now = System.currentTimeMillis();\n\n            if (lastRun > 0) {\n                long diff = (currentCount - lastCount);\n                double speed = diff * 8D / (now - lastRun);\n                System.out.println(new Date() + \" CurentSpeed: \" + speed / 1000 + \" Mb/s\");\n            }\n\n            lastRun = now;\n            lastCount = currentCount;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/AlreadySelectedException.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/AlreadySelectedException.java,v 1.4 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.4 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\n/**\n * <p>Thrown when more than one option in an option group\n * has been provided.</p>\n *\n * @author John Keyes ( john at integralsource.com )\n * @see ParseException\n */\npublic class AlreadySelectedException extends ParseException {\n\n    /**\n     * <p>Construct a new <code>AlreadySelectedException</code>\n     * with the specified detail message.</p>\n     *\n     * @param message the detail message\n     */\n    public AlreadySelectedException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/BasicParser.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/BasicParser.java,v 1.3 2002/09/19 22:59:43 jkeyes Exp $\n * $Revision: 1.3 $\n * $Date: 2002/09/19 22:59:43 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\n/**\n * The class BasicParser provides a very simple implementation of\n * the {@link Parser#flatten(Options, String[], boolean) flatten} method.\n *\n * @author John Keyes (john at integralsource.com)\n * @see Parser\n */\npublic class BasicParser extends Parser {\n\n    /**\n     * <p>A simple implementation of {@link Parser}'s abstract\n     * {@link Parser#flatten(Options, String[], boolean) flatten} method.</p>\n     * <p>\n     * <p><b>Note:</b> <code>options</code> and <code>stopAtNonOption</code>\n     * are not used in this <code>flatten</code> method.</p>\n     *\n     * @param options         The command line {@link Options}\n     * @param arguments       The command line arguments to be parsed\n     * @param stopAtNonOption Specifies whether to stop flattening\n     *                        when an non option is found.\n     * @return The <code>arguments</code> String array.\n     */\n    protected String[] flatten(Options options,\n                               String[] arguments,\n                               boolean stopAtNonOption) {\n        // just echo the arguments\n        return arguments;\n    }\n}"
  },
  {
    "path": "src/org/apache/commons/cli/CommandLine.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/CommandLine.java,v 1.4 2002/06/06 22:32:37 bayard Exp $\n * $Revision: 1.4 $\n * $Date: 2002/06/06 22:32:37 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\nimport java.util.*;\n\n/**\n * <p>Represents list of arguments parsed against\n * a {@link Options} descriptor.<p>\n * <p>\n * <p>It allows querying of a boolean {@link #hasOption(String opt)},\n * in addition to retrieving the {@link #getOptionValue(String opt)}\n * for options requiring arguments.</p>\n * <p>\n * <p>Additionally, any left-over or unrecognized arguments,\n * are available for further processing.</p>\n *\n * @author bob mcwhirter (bob @ werken.com)\n * @author <a href=\"mailto:jstrachan@apache.org\">James Strachan</a>\n * @author John Keyes (john at integralsource.com)\n */\npublic class CommandLine {\n\n    /**\n     * the unrecognised options/arguments\n     */\n    private List args = new LinkedList();\n\n    /**\n     * the processed options\n     */\n    private Map options = new HashMap();\n\n    /**\n     * Map of unique options for ease to get complete list of options\n     */\n    private Map hashcodeMap = new HashMap();\n\n    /**\n     * the processed options\n     */\n    private Option[] optionsArray;\n\n    /**\n     * <p>Creates a command line.</p>\n     */\n    CommandLine() {\n    }\n\n    /**\n     * <p>Query to see if an option has been set.</p>\n     *\n     * @param opt Short name of the option\n     * @return true if set, false if not\n     */\n    public boolean hasOption(String opt) {\n        return options.containsKey(opt);\n    }\n\n    /**\n     * <p>Query to see if an option has been set.</p>\n     *\n     * @param opt character name of the option\n     * @return true if set, false if not\n     */\n    public boolean hasOption(char opt) {\n        return hasOption(String.valueOf(opt));\n    }\n\n    /**\n     * <p>Return the <code>Object</code> type of this <code>Option</code>.</p>\n     *\n     * @param opt the name of the option\n     * @return the type of this <code>Option</code>\n     */\n    public Object getOptionObject(String opt) {\n        String res = getOptionValue(opt);\n\n        Object type = ((Option) ((List) options.get(opt)).iterator().next()).getType();\n        return res == null ? null : TypeHandler.createValue(res, type);\n    }\n\n    /**\n     * <p>Return the <code>Object</code> type of this <code>Option</code>.</p>\n     *\n     * @param opt the name of the option\n     * @return the type of opt\n     */\n    public Object getOptionObject(char opt) {\n        return getOptionObject(String.valueOf(opt));\n    }\n\n    /**\n     * <p>Retrieve the argument, if any, of this option.</p>\n     *\n     * @param opt the name of the option\n     * @return Value of the argument if option is set, and has an argument,\n     * otherwise null.\n     */\n    public String getOptionValue(String opt) {\n        String[] values = getOptionValues(opt);\n        return (values == null) ? null : values[0];\n    }\n\n    /**\n     * <p>Retrieve the argument, if any, of this option.</p>\n     *\n     * @param opt the character name of the option\n     * @return Value of the argument if option is set, and has an argument,\n     * otherwise null.\n     */\n    public String getOptionValue(char opt) {\n        return getOptionValue(String.valueOf(opt));\n    }\n\n    /**\n     * <p>Retrieves the array of values, if any, of an option.</p>\n     *\n     * @param opt string name of the option\n     * @return Values of the argument if option is set, and has an argument,\n     * otherwise null.\n     */\n    public String[] getOptionValues(String opt) {\n        List values = new java.util.ArrayList();\n\n        if (options.containsKey(opt)) {\n            List opts = (List) options.get(opt);\n            Iterator iter = opts.iterator();\n\n            while (iter.hasNext()) {\n                Option optt = (Option) iter.next();\n                values.addAll(optt.getValuesList());\n            }\n        }\n        return (values.size() == 0) ? null : (String[]) values.toArray(new String[]{});\n    }\n\n    /**\n     * <p>Retrieves the array of values, if any, of an option.</p>\n     *\n     * @param opt character name of the option\n     * @return Values of the argument if option is set, and has an argument,\n     * otherwise null.\n     */\n    public String[] getOptionValues(char opt) {\n        return getOptionValues(String.valueOf(opt));\n    }\n\n    /**\n     * <p>Retrieve the argument, if any, of an option.</p>\n     *\n     * @param opt          name of the option\n     * @param defaultValue is the default value to be returned if the option is not specified\n     * @return Value of the argument if option is set, and has an argument,\n     * otherwise <code>defaultValue</code>.\n     */\n    public String getOptionValue(String opt, String defaultValue) {\n        String answer = getOptionValue(opt);\n        return (answer != null) ? answer : defaultValue;\n    }\n\n    /**\n     * <p>Retrieve the argument, if any, of an option.</p>\n     *\n     * @param opt          character name of the option\n     * @param defaultValue is the default value to be returned if the option is not specified\n     * @return Value of the argument if option is set, and has an argument,\n     * otherwise <code>defaultValue</code>.\n     */\n    public String getOptionValue(char opt, String defaultValue) {\n        return getOptionValue(String.valueOf(opt), defaultValue);\n    }\n\n    /**\n     * <p>Retrieve any left-over non-recognized options and arguments</p>\n     *\n     * @return remaining items passed in but not parsed as an array\n     */\n    public String[] getArgs() {\n        String[] answer = new String[args.size()];\n        args.toArray(answer);\n        return answer;\n    }\n\n    /**\n     * <p>Retrieve any left-over non-recognized options and arguments</p>\n     *\n     * @return remaining items passed in but not parsed as a <code>List</code>.\n     */\n    public List getArgList() {\n        return args;\n    }\n\n    /**\n     * jkeyes\n     * - commented out until it is implemented properly\n     * <p>Dump state, suitable for debugging.</p>\n     *\n     * @return Stringified form of this object\n     */\n    /*\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n        \n        buf.append( \"[ CommandLine: [ options: \" );\n        buf.append( options.toString() );\n        buf.append( \" ] [ args: \");\n        buf.append( args.toString() );\n        buf.append( \" ] ]\" );\n        \n        return buf.toString();\n    }\n    */\n\n    /**\n     * <p>Add left-over unrecognized option/argument.</p>\n     *\n     * @param arg the unrecognised option/argument.\n     */\n    void addArg(String arg) {\n        args.add(arg);\n    }\n\n    /**\n     * <p>Add an option to the command line.  The values of\n     * the option are stored.</p>\n     *\n     * @param opt the processed option\n     */\n    void addOption(Option opt) {\n        hashcodeMap.put(new Integer(opt.hashCode()), opt);\n\n        String key = opt.getOpt();\n        if (\" \".equals(key)) {\n            key = opt.getLongOpt();\n        }\n\n        if (options.get(key) != null) {\n            ((java.util.List) options.get(key)).add(opt);\n        } else {\n            options.put(key, new java.util.ArrayList());\n            ((java.util.List) options.get(key)).add(opt);\n        }\n    }\n\n    /**\n     * <p>Returns an iterator over the Option members of CommandLine.</p>\n     *\n     * @return an <code>Iterator</code> over the processed {@link Option}\n     * members of this {@link CommandLine}\n     */\n    public Iterator iterator() {\n        return hashcodeMap.values().iterator();\n    }\n\n    /**\n     * <p>Returns an array of the processed {@link Option}s.</p>\n     *\n     * @return an array of the processed {@link Option}s.\n     */\n    public Option[] getOptions() {\n        Collection processed = hashcodeMap.values();\n\n        // reinitialise array\n        optionsArray = new Option[processed.size()];\n\n        // return the array\n        return (Option[]) processed.toArray(optionsArray);\n    }\n\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/CommandLineParser.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/CommandLineParser.java,v 1.4 2002/09/19 22:59:43 jkeyes Exp $\n * $Revision: 1.4 $\n * $Date: 2002/09/19 22:59:43 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\n/**\n * A class that implements the <code>CommandLineParser</code> interface\n * can parse a String array according to the {@link Options} specified\n * and return a {@link CommandLine}.\n *\n * @author John Keyes (john at integralsource.com)\n */\npublic interface CommandLineParser {\n\n    /**\n     * Parse the arguments according to the specified options.\n     *\n     * @param options   the specified Options\n     * @param arguments the command line arguments\n     * @return the list of atomic option and value tokens\n     * @throws ParseException if there are any problems encountered\n     *                        while parsing the command line tokens.\n     */\n    public CommandLine parse(Options options, String[] arguments)\n            throws ParseException;\n\n    /**\n     * Parse the arguments according to the specified options.\n     *\n     * @param options         the specified Options\n     * @param arguments       the command line arguments\n     * @param stopAtNonOption specifies whether to continue parsing the\n     *                        arguments if a non option is encountered.\n     * @return the list of atomic option and value tokens\n     * @throws ParseException if there are any problems encountered\n     *                        while parsing the command line tokens.\n     */\n    public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption)\n            throws ParseException;\n}"
  },
  {
    "path": "src/org/apache/commons/cli/GnuParser.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/GnuParser.java,v 1.10 2002/09/19 22:59:43 jkeyes Exp $\n * $Revision: 1.10 $\n * $Date: 2002/09/19 22:59:43 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\nimport java.util.ArrayList;\n\n/**\n * The class GnuParser provides an implementation of the\n * {@link Parser#flatten(Options, String[], boolean) flatten} method.\n *\n * @author John Keyes (john at integralsource.com)\n * @version $Revision: 1.10 $\n * @see Parser\n */\npublic class GnuParser extends Parser {\n\n    /**\n     * holder for flattened tokens\n     */\n    private ArrayList tokens = new ArrayList();\n\n    /**\n     * <p>Resets the members to their original state i.e. remove\n     * all of <code>tokens</code> entries.\n     */\n    private void init() {\n        tokens.clear();\n    }\n\n    /**\n     * <p>This flatten method does so using the following rules:\n     * <ol>\n     * <li>If an {@link Option} exists for the first character of\n     * the <code>arguments</code> entry <b>AND</b> an {@link Option}\n     * does not exist for the whole <code>argument</code> then\n     * add the first character as an option to the processed tokens\n     * list e.g. \"-D\" and add the rest of the entry to the also.</li>\n     * <li>Otherwise just add the token to the processed tokens list.\n     * </li>\n     * </ol>\n     * </p>\n     */\n    protected String[] flatten(Options options,\n                               String[] arguments,\n                               boolean stopAtNonOption) {\n        init();\n        boolean eatTheRest = false;\n        Option currentOption = null;\n\n        for (int i = 0; i < arguments.length; i++) {\n            if (\"--\".equals(arguments[i])) {\n                eatTheRest = true;\n                tokens.add(\"--\");\n            } else if (\"-\".equals(arguments[i])) {\n                tokens.add(\"-\");\n            } else if (arguments[i].startsWith(\"-\")) {\n                Option option = options.getOption(arguments[i]);\n\n                // this is not an Option\n                if (option == null) {\n                    // handle special properties Option\n                    Option specialOption = options.getOption(arguments[i].substring(0, 2));\n                    if (specialOption != null) {\n                        tokens.add(arguments[i].substring(0, 2));\n                        tokens.add(arguments[i].substring(2));\n                    } else if (stopAtNonOption) {\n                        eatTheRest = true;\n                        tokens.add(arguments[i]);\n                    } else {\n                        tokens.add(arguments[i]);\n                    }\n                } else {\n                    currentOption = option;\n                    // special option\n                    Option specialOption = options.getOption(arguments[i].substring(0, 2));\n                    if (specialOption != null && option == null) {\n                        tokens.add(arguments[i].substring(0, 2));\n                        tokens.add(arguments[i].substring(2));\n                    } else if (currentOption != null && currentOption.hasArg()) {\n                        if (currentOption.hasArg()) {\n                            tokens.add(arguments[i]);\n                            currentOption = null;\n                        } else if (currentOption.hasArgs()) {\n                            tokens.add(arguments[i]);\n                        } else if (stopAtNonOption) {\n                            eatTheRest = true;\n                            tokens.add(\"--\");\n                            tokens.add(arguments[i]);\n                        } else {\n                            tokens.add(arguments[i]);\n                        }\n                    } else if (currentOption != null) {\n                        tokens.add(arguments[i]);\n                    } else if (stopAtNonOption) {\n                        eatTheRest = true;\n                        tokens.add(\"--\");\n                        tokens.add(arguments[i]);\n                    } else {\n                        tokens.add(arguments[i]);\n                    }\n                }\n            } else {\n                tokens.add(arguments[i]);\n            }\n\n            if (eatTheRest) {\n                for (i++; i < arguments.length; i++) {\n                    tokens.add(arguments[i]);\n                }\n            }\n        }\n        return (String[]) tokens.toArray(new String[]{});\n    }\n}"
  },
  {
    "path": "src/org/apache/commons/cli/HelpFormatter.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/CommandLine.java,v 1.4 2002/06/06 22:32:37 bayard Exp $\n * $Revision: 1.4 $\n * $Date: 2002/06/06 22:32:37 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\nimport java.io.PrintWriter;\nimport java.util.*;\n\n/**\n * A formatter of help messages for the current command line options\n *\n * @author Slawek Zachcial\n * @author John Keyes (john at integralsource.com)\n **/\npublic class HelpFormatter {\n    // --------------------------------------------------------------- Constants\n\n    public static final int DEFAULT_WIDTH = 74;\n    public static final int DEFAULT_LEFT_PAD = 1;\n    public static final int DEFAULT_DESC_PAD = 3;\n    public static final String DEFAULT_SYNTAX_PREFIX = \"usage: \";\n    public static final String DEFAULT_OPT_PREFIX = \"-\";\n    public static final String DEFAULT_LONG_OPT_PREFIX = \"--\";\n    public static final String DEFAULT_ARG_NAME = \"arg\";\n\n    // ------------------------------------------------------------------ Static\n\n    // -------------------------------------------------------------- Attributes\n\n    public int defaultWidth;\n    public int defaultLeftPad;\n    public int defaultDescPad;\n    public String defaultSyntaxPrefix;\n    public String defaultNewLine;\n    public String defaultOptPrefix;\n    public String defaultLongOptPrefix;\n    public String defaultArgName;\n\n    // ------------------------------------------------------------ Constructors\n    public HelpFormatter() {\n        defaultWidth = DEFAULT_WIDTH;\n        defaultLeftPad = DEFAULT_LEFT_PAD;\n        defaultDescPad = DEFAULT_DESC_PAD;\n        defaultSyntaxPrefix = DEFAULT_SYNTAX_PREFIX;\n        defaultNewLine = System.getProperty(\"line.separator\");\n        defaultOptPrefix = DEFAULT_OPT_PREFIX;\n        defaultLongOptPrefix = DEFAULT_LONG_OPT_PREFIX;\n        defaultArgName = DEFAULT_ARG_NAME;\n    }\n\n    // ------------------------------------------------------------------ Public\n\n    public void printHelp(String cmdLineSyntax,\n                          Options options) {\n        printHelp(defaultWidth, cmdLineSyntax, null, options, null, false);\n    }\n\n    public void printHelp(String cmdLineSyntax,\n                          Options options,\n                          boolean autoUsage) {\n        printHelp(defaultWidth, cmdLineSyntax, null, options, null, autoUsage);\n    }\n\n    public void printHelp(String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          String footer) {\n        printHelp(cmdLineSyntax, header, options, footer, false);\n    }\n\n    public void printHelp(String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          String footer,\n                          boolean autoUsage) {\n        printHelp(defaultWidth, cmdLineSyntax, header, options, footer, autoUsage);\n    }\n\n    public void printHelp(int width,\n                          String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          String footer) {\n        printHelp(width, cmdLineSyntax, header, options, footer, false);\n    }\n\n    public void printHelp(int width,\n                          String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          String footer,\n                          boolean autoUsage) {\n        PrintWriter pw = new PrintWriter(System.out);\n        printHelp(pw, width, cmdLineSyntax, header,\n                options, defaultLeftPad, defaultDescPad, footer, autoUsage);\n        pw.flush();\n    }\n\n    public void printHelp(PrintWriter pw,\n                          int width,\n                          String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          int leftPad,\n                          int descPad,\n                          String footer)\n            throws IllegalArgumentException {\n        printHelp(pw, width, cmdLineSyntax, header, options, leftPad, descPad, footer, false);\n    }\n\n    public void printHelp(PrintWriter pw,\n                          int width,\n                          String cmdLineSyntax,\n                          String header,\n                          Options options,\n                          int leftPad,\n                          int descPad,\n                          String footer,\n                          boolean autoUsage)\n            throws IllegalArgumentException {\n        if (cmdLineSyntax == null || cmdLineSyntax.length() == 0) {\n            throw new IllegalArgumentException(\"cmdLineSyntax not provided\");\n        }\n\n        if (autoUsage) {\n            printUsage(pw, width, cmdLineSyntax, options);\n        } else {\n            printUsage(pw, width, cmdLineSyntax);\n        }\n\n        if (header != null && header.trim().length() > 0) {\n            printWrapped(pw, width, header);\n        }\n        printOptions(pw, width, options, leftPad, descPad);\n        if (footer != null && footer.trim().length() > 0) {\n            printWrapped(pw, width, footer);\n        }\n    }\n\n    /**\n     * <p>Prints the usage statement for the specified application.</p>\n     *\n     * @param pw      The PrintWriter to print the usage statement\n     * @param width   ??\n     * @param app The application name\n     * @param options The command line Options\n     */\n    public void printUsage(PrintWriter pw, int width, String app, Options options) {\n        // initialise the string buffer\n        StringBuffer buff = new StringBuffer(defaultSyntaxPrefix).append(app).append(\" \");\n\n        // create a list for processed option groups\n        ArrayList list = new ArrayList();\n\n        // temp variable\n        Option option;\n\n        // iterate over the options\n        for (Iterator i = options.getOptions().iterator(); i.hasNext(); ) {\n            // get the next Option\n            option = (Option) i.next();\n\n            // check if the option is part of an OptionGroup\n            OptionGroup group = options.getOptionGroup(option);\n\n            // if the option is part of a group and the group has not already\n            // been processed\n            if (group != null && !list.contains(group)) {\n\n                // add the group to the processed list\n                list.add(group);\n\n                // get the names of the options from the OptionGroup\n                Collection names = group.getNames();\n\n                buff.append(\"[\");\n\n                // for each option in the OptionGroup\n                for (Iterator iter = names.iterator(); iter.hasNext(); ) {\n                    buff.append(iter.next());\n                    if (iter.hasNext()) {\n                        buff.append(\" | \");\n                    }\n                }\n                buff.append(\"]\");\n            }\n            // if the Option is not part of an OptionGroup\n            else {\n                // if the Option is not a required option\n                if (!option.isRequired()) {\n                    buff.append(\"[\");\n                }\n\n                if (!\" \".equals(option.getOpt())) {\n                    buff.append(\"-\").append(option.getOpt());\n                } else {\n                    buff.append(\"--\").append(option.getLongOpt());\n                }\n\n                if (option.hasArg()) {\n                    buff.append(\" \");\n                }\n\n                // if the Option has a value\n                if (option.hasArg()) {\n                    buff.append(option.getArgName());\n                }\n\n                // if the Option is not a required option\n                if (!option.isRequired()) {\n                    buff.append(\"]\");\n                }\n                buff.append(\" \");\n            }\n        }\n\n        // call printWrapped\n        printWrapped(pw, width, buff.toString().indexOf(' ') + 1,\n                buff.toString());\n    }\n\n    public void printUsage(PrintWriter pw, int width, String cmdLineSyntax) {\n        int argPos = cmdLineSyntax.indexOf(' ') + 1;\n        printWrapped(pw, width, defaultSyntaxPrefix.length() + argPos,\n                defaultSyntaxPrefix + cmdLineSyntax);\n    }\n\n    public void printOptions(PrintWriter pw, int width, Options options, int leftPad, int descPad) {\n        StringBuffer sb = new StringBuffer();\n        renderOptions(sb, width, options, leftPad, descPad);\n        pw.println(sb.toString());\n    }\n\n    public void printWrapped(PrintWriter pw, int width, String text) {\n        printWrapped(pw, width, 0, text);\n    }\n\n    public void printWrapped(PrintWriter pw, int width, int nextLineTabStop, String text) {\n        StringBuffer sb = new StringBuffer(text.length());\n        renderWrappedText(sb, width, nextLineTabStop, text);\n        pw.println(sb.toString());\n    }\n\n    // --------------------------------------------------------------- Protected\n\n    protected StringBuffer renderOptions(StringBuffer sb,\n                                         int width,\n                                         Options options,\n                                         int leftPad,\n                                         int descPad) {\n        final String lpad = createPadding(leftPad);\n        final String dpad = createPadding(descPad);\n\n        //first create list containing only <lpad>-a,--aaa where -a is opt and --aaa is\n        //long opt; in parallel look for the longest opt string\n        //this list will be then used to sort options ascending\n        int max = 0;\n        StringBuffer optBuf;\n        List prefixList = new ArrayList();\n        Option option;\n        List optList = options.helpOptions();\n        Collections.sort(optList, new StringBufferComparator());\n        for (Iterator i = optList.iterator(); i.hasNext(); ) {\n            option = (Option) i.next();\n            optBuf = new StringBuffer(8);\n\n            if (option.getOpt().equals(\" \")) {\n                optBuf.append(lpad).append(\"   \" + defaultLongOptPrefix).append(option.getLongOpt());\n            } else {\n                optBuf.append(lpad).append(defaultOptPrefix).append(option.getOpt());\n                if (option.hasLongOpt()) {\n                    optBuf.append(',').append(defaultLongOptPrefix).append(option.getLongOpt());\n                }\n\n            }\n\n            if (option.hasArg()) {\n                if (option.hasArgName()) {\n                    optBuf.append(\" <\").append(option.getArgName()).append('>');\n                } else {\n                    optBuf.append(' ');\n                }\n            }\n\n            prefixList.add(optBuf);\n            max = optBuf.length() > max ? optBuf.length() : max;\n        }\n        int x = 0;\n        for (Iterator i = optList.iterator(); i.hasNext(); ) {\n            option = (Option) i.next();\n            optBuf = new StringBuffer(prefixList.get(x++).toString());\n\n            if (optBuf.length() < max) {\n                optBuf.append(createPadding(max - optBuf.length()));\n            }\n            optBuf.append(dpad);\n\n            int nextLineTabStop = max + descPad;\n            renderWrappedText(sb, width, nextLineTabStop,\n                    optBuf.append(option.getDescription()).toString());\n            if (i.hasNext()) {\n                sb.append(defaultNewLine);\n            }\n        }\n\n        return sb;\n    }\n\n    protected StringBuffer renderWrappedText(StringBuffer sb,\n                                             int width,\n                                             int nextLineTabStop,\n                                             String text) {\n        int pos = findWrapPos(text, width, 0);\n        if (pos == -1) {\n            sb.append(rtrim(text));\n            return sb;\n        } else {\n            sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine);\n        }\n\n        //all following lines must be padded with nextLineTabStop space characters\n        final String padding = createPadding(nextLineTabStop);\n\n        while (true) {\n            text = padding + text.substring(pos).trim();\n            pos = findWrapPos(text, width, nextLineTabStop);\n            if (pos == -1) {\n                sb.append(text);\n                return sb;\n            }\n\n            sb.append(rtrim(text.substring(0, pos))).append(defaultNewLine);\n        }\n\n    }\n\n    /**\n     * Finds the next text wrap position after <code>startPos</code> for the text\n     * in <code>sb</code> with the column width <code>width</code>.\n     * The wrap point is the last postion before startPos+width having a whitespace\n     * character (space, \\n, \\r).\n     *\n     * @param text       text to be analyzed\n     * @param width    width of the wrapped text\n     * @param startPos position from which to start the lookup whitespace character\n     * @return postion on which the text must be wrapped or -1 if the wrap position is at the end\n     * of the text\n     */\n    protected int findWrapPos(String text, int width, int startPos) {\n        int pos = -1;\n        // the line ends before the max wrap pos or a new line char found\n        if (((pos = text.indexOf('\\n', startPos)) != -1 && pos <= width) ||\n                ((pos = text.indexOf('\\t', startPos)) != -1 && pos <= width)) {\n            return pos;\n        } else if ((startPos + width) >= text.length()) {\n            return -1;\n        }\n\n        //look for the last whitespace character before startPos+width\n        pos = startPos + width;\n        char c;\n        while (pos >= startPos && (c = text.charAt(pos)) != ' ' && c != '\\n' && c != '\\r') {\n            --pos;\n        }\n        //if we found it - just return\n        if (pos > startPos) {\n            return pos;\n        } else {\n            //must look for the first whitespace chearacter after startPos + width\n            pos = startPos + width;\n            while (pos <= text.length() && (c = text.charAt(pos)) != ' ' && c != '\\n' && c != '\\r') {\n                ++pos;\n            }\n            return pos == text.length() ? -1 : pos;\n        }\n    }\n\n    protected String createPadding(int len) {\n        StringBuffer sb = new StringBuffer(len);\n        for (int i = 0; i < len; ++i) {\n            sb.append(' ');\n        }\n        return sb.toString();\n    }\n\n    protected String rtrim(String s) {\n        if (s == null || s.length() == 0) {\n            return s;\n        }\n\n        int pos = s.length();\n        while (pos >= 0 && Character.isWhitespace(s.charAt(pos - 1))) {\n            --pos;\n        }\n        return s.substring(0, pos);\n    }\n\n    // ------------------------------------------------------- Package protected\n\n    // ----------------------------------------------------------------- Private\n\n    // ----------------------------------------------------------- Inner classes\n\n    private static class StringBufferComparator\n            implements Comparator {\n        public int compare(Object o1, Object o2) {\n            String str1 = stripPrefix(o1.toString());\n            String str2 = stripPrefix(o2.toString());\n            return (str1.compareTo(str2));\n        }\n\n        private String stripPrefix(String strOption) {\n            // Strip any leading '-' characters\n            int iStartIndex = strOption.lastIndexOf('-');\n            if (iStartIndex == -1) {\n                iStartIndex = 0;\n            }\n            return strOption.substring(iStartIndex);\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/MissingArgumentException.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/MissingArgumentException.java,v 1.2 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * <p>Thrown when an option requiring an argument\n * is not provided with an argument.</p>\n *\n * @author John Keyes (john at integralsource.com)\n * @see ParseException\n */\npublic class MissingArgumentException extends ParseException {\n\n    /**\n     * <p>Construct a new <code>MissingArgumentException</code>\n     * with the specified detail message.</p>\n     *\n     * @param message the detail message\n     */\n    public MissingArgumentException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/MissingOptionException.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/MissingOptionException.java,v 1.2 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * <p>Thrown when a required option has not been provided.</p>\n *\n * @author John Keyes ( john at integralsource.com )\n * @see ParseException\n */\npublic class MissingOptionException extends ParseException {\n\n    /**\n     * <p>Construct a new <code>MissingSelectedException</code>\n     * with the specified detail message.</p>\n     *\n     * @param message the detail message\n     */\n    public MissingOptionException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/Option.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/Option.java,v 1.6 2002/06/06 22:50:14 bayard Exp $\n * $Revision: 1.6 $\n * $Date: 2002/06/06 22:50:14 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\n/*\n * Copyright (C) The Apache Software Foundation. All rights reserved.\n *\n * This software is published under the terms of the Apache Software License\n * version 1.1, a copy of which has been included with this distribution in\n * the LICENSE file.\n * \n * $Id: Option.java,v 1.6 2002/06/06 22:50:14 bayard Exp $\n */\n\npackage org.apache.commons.cli;\n\nimport java.util.ArrayList;\n\n/**\n * <p>Describes a single command-line option.  It maintains\n * information regarding the short-name of the option, the long-name,\n * if any exists, a flag indicating if an argument is required for\n * this option, and a self-documenting description of the option.</p>\n * <p>\n * <p>An Option is not created independantly, but is create through\n * an instance of {@link Options}.<p>\n *\n * @author bob mcwhirter (bob @ werken.com)\n * @author <a href=\"mailto:jstrachan@apache.org\">James Strachan</a>\n * @version $Revision: 1.6 $\n * @see org.apache.commons.cli.Options\n * @see org.apache.commons.cli.CommandLine\n */\n\npublic class Option implements Cloneable {\n\n    /**\n     * constant that specifies the number of argument values has not been specified\n     */\n    public final static int UNINITIALIZED = -1;\n\n    /**\n     * constant that specifies the number of argument values is infinite\n     */\n    public final static int UNLIMITED_VALUES = -2;\n\n    /**\n     * opt the single character representation of the option\n     */\n    private String opt;\n\n    /**\n     * longOpt is the long representation of the option\n     */\n    private String longOpt;\n\n    /**\n     * hasArg specifies whether this option has an associated argument\n     */\n    private boolean hasArg;\n\n    /**\n     * argName specifies the name of the argument for this option\n     */\n    private String argName;\n\n    /**\n     * description of the option\n     */\n    private String description;\n\n    /**\n     * required specifies whether this option is required to be present\n     */\n    private boolean required;\n\n    /**\n     * specifies whether the argument value of this Option is optional\n     */\n    private boolean optionalArg;\n\n    /**\n     * numberOfArgs specifies the number of argument values this option\n     * can have\n     */\n    private int numberOfArgs = UNINITIALIZED;\n\n    /**\n     * the type of this Option\n     */\n    private Object type;\n\n    /**\n     * the list of argument values\n     **/\n    private ArrayList values = new ArrayList();\n\n    /**\n     * option char (only valid for single character options)\n     */\n    private char id;\n\n    /**\n     * the character that is the value separator\n     */\n    private char valuesep;\n\n    /**\n     * Creates an Option using the specified parameters.\n     *\n     * @param opt         short representation of the option\n     * @param description describes the function of the option\n     */\n    public Option(String opt, String description)\n            throws IllegalArgumentException {\n        this(opt, null, false, description);\n    }\n\n    /**\n     * Creates an Option using the specified parameters.\n     *\n     * @param opt         short representation of the option\n     * @param hasArg      specifies whether the Option takes an argument or not\n     * @param description describes the function of the option\n     */\n    public Option(String opt, boolean hasArg, String description)\n            throws IllegalArgumentException {\n        this(opt, null, hasArg, description);\n    }\n\n    /**\n     * <p>Creates an Option using the specified parameters.</p>\n     *\n     * @param opt         short representation of the option\n     * @param longOpt     the long representation of the option\n     * @param hasArg      specifies whether the Option takes an argument or not\n     * @param description describes the function of the option\n     */\n    public Option(String opt, String longOpt, boolean hasArg, String description)\n            throws IllegalArgumentException {\n        // ensure that the option is valid\n        validateOption(opt);\n\n        this.opt = opt;\n        this.longOpt = longOpt;\n\n        // if hasArg is set then the number of arguments is 1\n        if (hasArg) {\n            this.numberOfArgs = 1;\n        }\n\n        this.hasArg = hasArg;\n        this.description = description;\n    }\n\n    /**\n     * <p>Validates whether <code>opt</code> is a permissable Option\n     * shortOpt.  The rules that specify if the <code>opt</code>\n     * is valid are:</p>\n     * <ul>\n     * <li><code>opt</code> is not NULL</li>\n     * <li>a single character <code>opt</code> that is either\n     * ' '(special case), '?', '@' or a letter</li>\n     * <li>a multi character <code>opt</code> that only contains\n     * letters.</li>\n     * </ul>\n     *\n     * @param opt The option string to validate\n     * @throws IllegalArgumentException if the Option is not valid.\n     */\n    private void validateOption(String opt)\n            throws IllegalArgumentException {\n        // check that opt is not NULL\n        if (opt == null) {\n            throw new IllegalArgumentException(\"opt is null\");\n        }\n        // handle the single character opt\n        else if (opt.length() == 1) {\n            char ch = opt.charAt(0);\n            if (!isValidOpt(ch)) {\n                throw new IllegalArgumentException(\"illegal option value '\"\n                        + ch + \"'\");\n            }\n            id = ch;\n        }\n        // handle the multi character opt\n        else {\n            char[] chars = opt.toCharArray();\n            for (int i = 0; i < chars.length; i++) {\n                if (!isValidChar(chars[i])) {\n                    throw new IllegalArgumentException(\"opt contains illegal character value '\" + chars[i] + \"'\");\n                }\n            }\n        }\n    }\n\n    /**\n     * <p>Returns whether the specified character is a valid Option.</p>\n     *\n     * @param c the option to validate\n     * @return true if <code>c</code> is a letter, ' ', '?' or '@', otherwise false.\n     */\n    private boolean isValidOpt(char c) {\n        return (isValidChar(c) || c == ' ' || c == '?' || c == '@');\n    }\n\n    /**\n     * <p>Returns whether the specified character is a valid character.</p>\n     *\n     * @param c the character to validate\n     * @return true if <code>c</code> is a letter.\n     */\n    private boolean isValidChar(char c) {\n        return Character.isJavaIdentifierPart(c);\n    }\n\n    /**\n     * <p>Returns the id of this Option.  This is only set when the\n     * Option shortOpt is a single character.  This is used for switch\n     * statements.</p>\n     *\n     * @return the id of this Option\n     */\n    public int getId() {\n        return id;\n    }\n\n    /**\n     * <p>Retrieve the name of this Option.</p>\n     * <p>\n     * <p>It is this String which can be used with\n     * {@link CommandLine#hasOption(String opt)} and\n     * {@link CommandLine#getOptionValue(String opt)} to check\n     * for existence and argument.<p>\n     *\n     * @return The name of this option\n     */\n    public String getOpt() {\n        return this.opt;\n    }\n\n    /**\n     * <p>Retrieve the type of this Option.</p>\n     *\n     * @return The type of this option\n     */\n    public Object getType() {\n        return this.type;\n    }\n\n    /**\n     * <p>Sets the type of this Option.</p>\n     *\n     * @param type the type of this Option\n     */\n    public void setType(Object type) {\n        this.type = type;\n    }\n\n    /**\n     * <p>Retrieve the long name of this Option.</p>\n     *\n     * @return Long name of this option, or null, if there is no long name\n     */\n    public String getLongOpt() {\n        return this.longOpt;\n    }\n\n    /**\n     * <p>Sets the long name of this Option.</p>\n     *\n     * @param longOpt the long name of this Option\n     */\n    public void setLongOpt(String longOpt) {\n        this.longOpt = longOpt;\n    }\n\n    /**\n     * <p>Sets whether this Option can have an optional argument.</p>\n     *\n     * @param optionalArg specifies whether the Option can have\n     *                    an optional argument.\n     */\n    public void setOptionalArg(boolean optionalArg) {\n        this.optionalArg = optionalArg;\n    }\n\n    /**\n     * @return whether this Option can have an optional argument\n     */\n    public boolean hasOptionalArg() {\n        return this.optionalArg;\n    }\n\n    /**\n     * <p>Query to see if this Option has a long name</p>\n     *\n     * @return boolean flag indicating existence of a long name\n     */\n    public boolean hasLongOpt() {\n        return (this.longOpt != null);\n    }\n\n    /**\n     * <p>Query to see if this Option requires an argument</p>\n     *\n     * @return boolean flag indicating if an argument is required\n     */\n    public boolean hasArg() {\n        return this.numberOfArgs > 0 || numberOfArgs == UNLIMITED_VALUES;\n    }\n\n    /**\n     * <p>Retrieve the self-documenting description of this Option</p>\n     *\n     * @return The string description of this option\n     */\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * <p>Query to see if this Option requires an argument</p>\n     *\n     * @return boolean flag indicating if an argument is required\n     */\n    public boolean isRequired() {\n        return this.required;\n    }\n\n    /**\n     * <p>Sets whether this Option is mandatory.</p>\n     *\n     * @param required specifies whether this Option is mandatory\n     */\n    public void setRequired(boolean required) {\n        this.required = required;\n    }\n\n    /**\n     * <p>Gets the display name for the argument value.</p>\n     *\n     * @return the display name for the argument value.\n     */\n    public String getArgName() {\n        return this.argName;\n    }\n\n    /**\n     * <p>Sets the display name for the argument value.</p>\n     *\n     * @param argName the display name for the argument value.\n     */\n    public void setArgName(String argName) {\n        this.argName = argName;\n    }\n\n    /**\n     * <p>Returns whether the display name for the argument value\n     * has been set.</p>\n     *\n     * @return if the display name for the argument value has been\n     * set.\n     */\n    public boolean hasArgName() {\n        return (this.argName != null && this.argName.length() > 0);\n    }\n\n    /**\n     * <p>Query to see if this Option can take many values</p>\n     *\n     * @return boolean flag indicating if multiple values are allowed\n     */\n    public boolean hasArgs() {\n        return (this.numberOfArgs > 1 || this.numberOfArgs == UNLIMITED_VALUES);\n    }\n\n    /**\n     * <p>Returns the value separator character.</p>\n     *\n     * @return the value separator character.\n     */\n    public char getValueSeparator() {\n        return this.valuesep;\n    }\n\n    /**\n     * <p>Sets the value separator.  For example if the argument value\n     * was a Java property, the value separator would be '='.</p>\n     *\n     * @param sep The value separator.\n     */\n    public void setValueSeparator(char sep) {\n        this.valuesep = sep;\n    }\n\n    /**\n     * <p>Returns the number of argument values this Option can take.</p>\n     *\n     * @return num the number of argument values\n     */\n    public int getArgs() {\n        return this.numberOfArgs;\n    }\n\n    /**\n     * <p>Sets the number of argument values this Option can take.</p>\n     *\n     * @param num the number of argument values\n     */\n    public void setArgs(int num) {\n        this.numberOfArgs = num;\n    }\n\n    /**\n     * <p>Dump state, suitable for debugging.</p>\n     *\n     * @return Stringified form of this object\n     */\n    public String toString() {\n        StringBuffer buf = new StringBuffer().append(\"[ option: \");\n\n        buf.append(this.opt);\n\n        if (this.longOpt != null) {\n            buf.append(\" \")\n                    .append(this.longOpt);\n        }\n\n        buf.append(\" \");\n\n        if (hasArg) {\n            buf.append(\"+ARG\");\n        }\n\n        buf.append(\" :: \")\n                .append(this.description);\n\n        if (this.type != null) {\n            buf.append(\" :: \")\n                    .append(this.type);\n        }\n\n        buf.append(\" ]\");\n        return buf.toString();\n    }\n\n    /**\n     * <p>Adds the specified value to this Option.</p>\n     *\n     * @param value is a/the value of this Option\n     */\n    public boolean addValue(String value) {\n\n        switch (numberOfArgs) {\n            case UNINITIALIZED:\n                return false;\n            case UNLIMITED_VALUES:\n                if (getValueSeparator() > 0) {\n                    int index = 0;\n                    while ((index = value.indexOf(getValueSeparator())) != -1) {\n                        this.values.add(value.substring(0, index));\n                        value = value.substring(index + 1);\n                    }\n                }\n                this.values.add(value);\n                return true;\n            default:\n                if (getValueSeparator() > 0) {\n                    int index = 0;\n                    while ((index = value.indexOf(getValueSeparator())) != -1) {\n                        if (values.size() > numberOfArgs - 1) {\n                            return false;\n                        }\n                        this.values.add(value.substring(0, index));\n                        value = value.substring(index + 1);\n                    }\n                }\n                if (values.size() > numberOfArgs - 1) {\n                    return false;\n                }\n                this.values.add(value);\n                return true;\n        }\n    }\n\n    /**\n     * @return the value/first value of this Option or\n     * <code>null</code> if there are no values.\n     */\n    public String getValue() {\n        return this.values.size() == 0 ? null : (String) this.values.get(0);\n    }\n\n    /**\n     * @return the specified value of this Option or\n     * <code>null</code> if there are no values.\n     */\n    public String getValue(int index)\n            throws IndexOutOfBoundsException {\n        return (this.values.size() == 0) ? null : (String) this.values.get(index);\n    }\n\n    /**\n     * @return the value/first value of this Option or the\n     * <code>defaultValue</code> if there are no values.\n     */\n    public String getValue(String defaultValue) {\n        String value = getValue();\n        return (value != null) ? value : defaultValue;\n    }\n\n    /**\n     * @return the values of this Option as a String array\n     * or null if there are no values\n     */\n    public String[] getValues() {\n        return this.values.size() == 0 ? null : (String[]) this.values.toArray(new String[]{});\n    }\n\n    /**\n     * @return the values of this Option as a List\n     * or null if there are no values\n     */\n    public java.util.List getValuesList() {\n        return this.values;\n    }\n\n    /**\n     * @return a copy of this Option\n     */\n    public Object clone() {\n        Option option = new Option(getOpt(), getDescription());\n        option.setArgs(getArgs());\n        option.setOptionalArg(hasOptionalArg());\n        option.setRequired(isRequired());\n        option.setLongOpt(getLongOpt());\n        option.setType(getType());\n        option.setValueSeparator(getValueSeparator());\n        return option;\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/OptionBuilder.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/OptionBuilder.java,v 1.12 2002/10/15 22:50:45 jkeyes Exp $\n * $Revision: 1.12 $\n * $Date: 2002/10/15 22:50:45 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * <p>OptionBuilder allows the user to create Options using descriptive\n * methods.</p>\n * <p>Details on the Builder pattern can be found at\n * <a href=\"http://c2.com/cgi-bin/wiki?BuilderPattern\">http://c2.com/cgi-bin/wiki?BuilderPattern</a>.</p>\n *\n * @author John Keyes ( john at integralsource.com )\n * @since 1.0\n */\npublic class OptionBuilder {\n\n    /**\n     * long option\n     */\n    private static String longopt;\n    /**\n     * option description\n     */\n    private static String description;\n    /**\n     * argument name\n     */\n    private static String argName;\n    /**\n     * is required?\n     */\n    private static boolean required;\n    /**\n     * the number of arguments\n     */\n    private static int numberOfArgs = Option.UNINITIALIZED;\n    /**\n     * option type\n     */\n    private static Object type;\n    /**\n     * option can have an optional argument value\n     */\n    private static boolean optionalArg;\n    /**\n     * value separator for argument value\n     */\n    private static char valuesep;\n\n    /**\n     * option builder instance\n     */\n    private static OptionBuilder instance = new OptionBuilder();\n\n    // private constructor\n    private OptionBuilder() {\n    }\n\n    /**\n     * <p>Resets the member variables to their default values.</p>\n     */\n    private static void reset() {\n        description = null;\n        argName = null;\n        longopt = null;\n        type = null;\n        required = false;\n        numberOfArgs = Option.UNINITIALIZED;\n\n        // PMM 9/6/02 - these were missing\n        optionalArg = false;\n        valuesep = (char) 0;\n    }\n\n    /**\n     * <p>The next Option created will have the following long option value.</p>\n     *\n     * @param longopt the long option value\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withLongOpt(String longopt) {\n        instance.longopt = longopt;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will require an argument value.</p>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasArg() {\n        instance.numberOfArgs = 1;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will require an argument value if\n     * <code>hasArg</code> is true.</p>\n     *\n     * @param hasArg if true then the Option has an argument value\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasArg(boolean hasArg) {\n        instance.numberOfArgs = (hasArg == true) ? 1 : Option.UNINITIALIZED;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will have the specified argument value\n     * name.</p>\n     *\n     * @param name the name for the argument value\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withArgName(String name) {\n        instance.argName = name;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will be required.</p>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder isRequired() {\n        instance.required = true;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created uses <code>sep</code> as a means to\n     * separate argument values.</p>\n     * <p>\n     * <b>Example:</b>\n     * <pre>\n     * Option opt = OptionBuilder.withValueSeparator( ':' )\n     *                           .create( 'D' );\n     *\n     * CommandLine line = parser.parse( args );\n     * String propertyName = opt.getValue( 0 );\n     * String propertyValue = opt.getValue( 1 );\n     * </pre>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withValueSeparator(char sep) {\n        instance.valuesep = sep;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created uses '<code>=</code>' as a means to\n     * separate argument values.</p>\n     * <p>\n     * <b>Example:</b>\n     * <pre>\n     * Option opt = OptionBuilder.withValueSeparator( )\n     *                           .create( 'D' );\n     *\n     * CommandLine line = parser.parse( args );\n     * String propertyName = opt.getValue( 0 );\n     * String propertyValue = opt.getValue( 1 );\n     * </pre>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withValueSeparator() {\n        instance.valuesep = '=';\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will be required if <code>required</code>\n     * is true.</p>\n     *\n     * @param required if true then the Option is required\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder isRequired(boolean required) {\n        instance.required = required;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created can have unlimited argument values.</p>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasArgs() {\n        instance.numberOfArgs = Option.UNLIMITED_VALUES;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created can have <code>num</code>\n     * argument values.</p>\n     *\n     * @param num the number of args that the option can have\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasArgs(int num) {\n        instance.numberOfArgs = num;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option can have an optional argument.</p>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasOptionalArg() {\n        instance.numberOfArgs = 1;\n        instance.optionalArg = true;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option can have an unlimited number of\n     * optional arguments.</p>\n     *\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasOptionalArgs() {\n        instance.numberOfArgs = Option.UNLIMITED_VALUES;\n        instance.optionalArg = true;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option can have the specified number of\n     * optional arguments.</p>\n     *\n     * @param numArgs - the maximum number of optional arguments\n     *                the next Option created can have.\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder hasOptionalArgs(int numArgs) {\n        instance.numberOfArgs = numArgs;\n        instance.optionalArg = true;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will have a value that will be an instance\n     * of <code>type</code>.</p>\n     *\n     * @param type the type of the Options argument value\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withType(Object type) {\n        instance.type = type;\n        return instance;\n    }\n\n    /**\n     * <p>The next Option created will have the specified description</p>\n     *\n     * @param description a description of the Option's purpose\n     * @return the OptionBuilder instance\n     */\n    public static OptionBuilder withDescription(String description) {\n        instance.description = description;\n        return instance;\n    }\n\n    /**\n     * <p>Create an Option using the current settings and with\n     * the specified Option <code>char</code>.</p>\n     *\n     * @param opt the character representation of the Option\n     * @return the Option instance\n     * @throws IllegalArgumentException if <code>opt</code> is not\n     *                                  a valid character.  See Option.\n     */\n    public static Option create(char opt)\n            throws IllegalArgumentException {\n        return create(String.valueOf(opt));\n    }\n\n    /**\n     * <p>Create an Option using the current settings</p>\n     *\n     * @return the Option instance\n     * @throws IllegalArgumentException if <code>longOpt</code> has\n     *                                  not been set.\n     */\n    public static Option create()\n            throws IllegalArgumentException {\n        if (longopt == null) {\n            throw new IllegalArgumentException(\"must specify longopt\");\n        }\n\n        return create(\" \");\n    }\n\n    /**\n     * <p>Create an Option using the current settings and with\n     * the specified Option <code>char</code>.</p>\n     *\n     * @param opt the <code>java.lang.String</code> representation\n     *            of the Option\n     * @return the Option instance\n     * @throws IllegalArgumentException if <code>opt</code> is not\n     *                                  a valid character.  See Option.\n     */\n    public static Option create(String opt)\n            throws IllegalArgumentException {\n        // create the option\n        Option option = new Option(opt, description);\n\n        // set the option properties\n        option.setLongOpt(longopt);\n        option.setRequired(required);\n        option.setOptionalArg(optionalArg);\n        option.setArgs(numberOfArgs);\n        option.setType(type);\n        option.setValueSeparator(valuesep);\n        option.setArgName(argName);\n        // reset the OptionBuilder properties\n        instance.reset();\n\n        // return the Option instance\n        return option;\n    }\n}"
  },
  {
    "path": "src/org/apache/commons/cli/OptionGroup.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/OptionGroup.java,v 1.2 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Iterator;\n\n/**\n * A group of mutually exclusive options.\n *\n * @author John Keyes ( john at integralsource.com )\n * @version $Revision: 1.2 $\n */\npublic class OptionGroup {\n\n    /**\n     * hold the options\n     */\n    private HashMap optionMap = new HashMap();\n\n    /**\n     * the name of the selected option\n     */\n    private String selected;\n\n    /**\n     * specified whether this group is required\n     */\n    private boolean required;\n\n    /**\n     * add <code>opt</code> to this group\n     *\n     * @param opt the option to add to this group\n     * @return this option group with opt added\n     */\n    public OptionGroup addOption(Option opt) {\n        // key   - option name\n        // value - the option\n        optionMap.put(\"-\" + opt.getOpt(), opt);\n        return this;\n    }\n\n    /**\n     * @return the names of the options in this group as a\n     * <code>Collection</code>\n     */\n    public Collection getNames() {\n        // the key set is the collection of names\n        return optionMap.keySet();\n    }\n\n    /**\n     * @return the options in this group as a <code>Collection</code>\n     */\n    public Collection getOptions() {\n        // the values are the collection of options\n        return optionMap.values();\n    }\n\n    /**\n     * @return the selected option name\n     */\n    public String getSelected() {\n        return selected;\n    }\n\n    /**\n     * set the selected option of this group to <code>name</code>.\n     *\n     * @param opt the option that is selected\n     * @throws AlreadySelectedException if an option from this group has\n     *                                  already been selected.\n     */\n    public void setSelected(Option opt) throws AlreadySelectedException {\n        // if no option has already been selected or the\n        // same option is being reselected then set the\n        // selected member variable\n\n        if (this.selected == null || this.selected.equals(opt.getOpt())) {\n            this.selected = opt.getOpt();\n        } else {\n            throw new AlreadySelectedException(\"an option from this group has \" +\n                    \"already been selected: '\" +\n                    selected + \"'\");\n        }\n    }\n\n    /**\n     * Returns whether this option group is required.\n     *\n     * @returns whether this option group is required\n     */\n    public boolean isRequired() {\n        return this.required;\n    }\n\n    /**\n     * @param required specifies if this group is required\n     */\n    public void setRequired(boolean required) {\n        this.required = required;\n    }\n\n    /**\n     * <p>Returns the stringified version of this OptionGroup.</p>\n     *\n     * @return the stringified representation of this group\n     */\n    public String toString() {\n        StringBuffer buff = new StringBuffer();\n\n        Iterator iter = getOptions().iterator();\n\n        buff.append(\"[\");\n        while (iter.hasNext()) {\n            Option option = (Option) iter.next();\n\n            buff.append(\"-\");\n            buff.append(option.getOpt());\n            buff.append(\" \");\n            buff.append(option.getDescription());\n\n            if (iter.hasNext()) {\n                buff.append(\", \");\n            }\n        }\n        buff.append(\"]\");\n\n        return buff.toString();\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/Options.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/Options.java,v 1.5 2002/06/06 22:32:37 bayard Exp $\n * $Revision: 1.5 $\n * $Date: 2002/06/06 22:32:37 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\nimport java.util.*;\n\n/**\n * <p>Main entry-point into the library.</p>\n * <p>\n * <p>Options represents a collection of {@link Option} objects, which\n * describe the possible options for a command-line.<p>\n * <p>\n * <p>It may flexibly parse long and short options, with or without\n * values.  Additionally, it may parse only a portion of a commandline,\n * allowing for flexible multi-stage parsing.<p>\n *\n * @author bob mcwhirter (bob @ werken.com)\n * @author <a href=\"mailto:jstrachan@apache.org\">James Strachan</a>\n * @version $Revision: 1.5 $\n * @see org.apache.commons.cli.CommandLine\n */\npublic class Options {\n\n    /**\n     * a map of the options with the character key\n     */\n    private Map shortOpts = new HashMap();\n\n    /**\n     * a map of the options with the long key\n     */\n    private Map longOpts = new HashMap();\n\n    /**\n     * a map of the required options\n     */\n    private List requiredOpts = new ArrayList();\n\n    /**\n     * a map of the option groups\n     */\n    private Map optionGroups = new HashMap();\n\n    /**\n     * <p>Construct a new Options descriptor</p>\n     */\n    public Options() {\n    }\n\n    /**\n     * <p>Add the specified option group.</p>\n     *\n     * @param group the OptionGroup that is to be added\n     * @return the resulting Options instance\n     */\n    public Options addOptionGroup(OptionGroup group) {\n        Iterator options = group.getOptions().iterator();\n\n        if (group.isRequired()) {\n            requiredOpts.add(group);\n        }\n\n        while (options.hasNext()) {\n            Option option = (Option) options.next();\n            // an Option cannot be required if it is in an\n            // OptionGroup, either the group is required or\n            // nothing is required\n            option.setRequired(false);\n            addOption(option);\n\n            optionGroups.put(option.getOpt(), group);\n        }\n\n        return this;\n    }\n\n    /**\n     * <p>Add an option that only contains a short-name</p>\n     * <p>It may be specified as requiring an argument.</p>\n     *\n     * @param opt         Short single-character name of the option.\n     * @param hasArg      flag signally if an argument is required after this option\n     * @param description Self-documenting description\n     * @return the resulting Options instance\n     */\n    public Options addOption(String opt, boolean hasArg, String description) {\n        addOption(opt, null, hasArg, description);\n        return this;\n    }\n\n    /**\n     * <p>Add an option that contains a short-name and a long-name</p>\n     * <p>It may be specified as requiring an argument.</p>\n     *\n     * @param opt         Short single-character name of the option.\n     * @param longOpt     Long multi-character name of the option.\n     * @param hasArg      flag signally if an argument is required after this option\n     * @param description Self-documenting description\n     * @return the resulting Options instance\n     */\n    public Options addOption(String opt, String longOpt, boolean hasArg, String description) {\n        addOption(new Option(opt, longOpt, hasArg, description));\n        return this;\n    }\n\n    /**\n     * <p>Adds an option instance</p>\n     *\n     * @param opt the option that is to be added\n     * @return the resulting Options instance\n     */\n    public Options addOption(Option opt) {\n        String shortOpt = \"-\" + opt.getOpt();\n\n        // add it to the long option list\n        if (opt.hasLongOpt()) {\n            longOpts.put(\"--\" + opt.getLongOpt(), opt);\n        }\n\n        // if the option is required add it to the required list\n        if (opt.isRequired()) {\n            requiredOpts.add(shortOpt);\n        }\n\n        shortOpts.put(shortOpt, opt);\n\n        return this;\n    }\n\n    /**\n     * <p>Retrieve a read-only list of options in this set</p>\n     *\n     * @return read-only Collection of {@link Option} objects in this descriptor\n     */\n    public Collection getOptions() {\n        List opts = new ArrayList(shortOpts.values());\n\n        // now look through the long opts to see if there are any Long-opt\n        // only options\n        Iterator iter = longOpts.values().iterator();\n        while (iter.hasNext()) {\n            Object item = iter.next();\n            if (!opts.contains(item)) {\n                opts.add(item);\n            }\n        }\n        return Collections.unmodifiableCollection(opts);\n    }\n\n    /**\n     * <p>Returns the Options for use by the HelpFormatter.</p>\n     *\n     * @return the List of Options\n     */\n    List helpOptions() {\n        return new ArrayList(shortOpts.values());\n    }\n\n    /**\n     * <p>Returns the required options as a\n     * <code>java.util.Collection</code>.</p>\n     *\n     * @return Collection of required options\n     */\n    public List getRequiredOptions() {\n        return requiredOpts;\n    }\n\n    /**\n     * <p>Retrieve the named {@link Option}</p>\n     *\n     * @param opt short or long name of the {@link Option}\n     * @return the option represented by opt\n     */\n    public Option getOption(String opt) {\n\n        Option option = null;\n\n        // short option\n        if (opt.length() == 1) {\n            option = (Option) shortOpts.get(\"-\" + opt);\n        }\n        // long option\n        else if (opt.startsWith(\"--\")) {\n            option = (Option) longOpts.get(opt);\n        }\n        // a just-in-case\n        else {\n            option = (Option) shortOpts.get(opt);\n        }\n\n        return (option == null) ? null : (Option) option.clone();\n    }\n\n    /**\n     * <p>Returns whether the named {@link Option} is a member\n     * of this {@link Options}</p>\n     *\n     * @param opt short or long name of the {@link Option}\n     * @return true if the named {@link Option} is a member\n     * of this {@link Options}\n     */\n    public boolean hasOption(String opt) {\n\n        // short option\n        if (opt.length() == 1) {\n            return shortOpts.containsKey(\"-\" + opt);\n        }\n        // long option\n        else if (opt.startsWith(\"--\")) {\n            return longOpts.containsKey(opt);\n        }\n        // a just-in-case\n        else {\n            return shortOpts.containsKey(opt);\n        }\n    }\n\n    /**\n     * <p>Returns the OptionGroup the <code>opt</code>\n     * belongs to.</p>\n     *\n     * @param opt the option whose OptionGroup is being queried.\n     * @return the OptionGroup if <code>opt</code> is part\n     * of an OptionGroup, otherwise return null\n     */\n    public OptionGroup getOptionGroup(Option opt) {\n        return (OptionGroup) optionGroups.get(opt.getOpt());\n    }\n\n    /**\n     * <p>Dump state, suitable for debugging.</p>\n     *\n     * @return Stringified form of this object\n     */\n    public String toString() {\n        StringBuffer buf = new StringBuffer();\n\n        buf.append(\"[ Options: [ short \");\n        buf.append(shortOpts.toString());\n        buf.append(\" ] [ long \");\n        buf.append(longOpts);\n        buf.append(\" ]\");\n\n        return buf.toString();\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/ParseException.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/ParseException.java,v 1.2 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * <p>Base for Exceptions thrown during parsing of a command-line.</p>\n *\n * @author bob mcwhirter (bob @ werken.com)\n * @version $Revision: 1.2 $\n */\npublic class ParseException extends Exception {\n\n    /**\n     * <p>Construct a new <code>ParseException</code>\n     * with the specified detail message.</p>\n     *\n     * @param message the detail message\n     */\n    public ParseException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/Parser.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/Parser.java,v 1.7 2002/10/24 23:17:49 jkeyes Exp $\n * $Revision: 1.7 $\n * $Date: 2002/10/24 23:17:49 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\nimport java.util.Arrays;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\n\n/**\n * <p><code>Parser</code> creates {@link CommandLine}s.</p>\n *\n * @author John Keyes (john at integralsource.com)\n * @version $Revision: 1.7 $\n * @see Parser\n */\npublic abstract class Parser implements CommandLineParser {\n\n    /**\n     * commandline instance\n     */\n    private CommandLine cmd;\n    /**\n     * current Options\n     */\n    private Options options;\n    /**\n     * list of required options strings\n     */\n    private List requiredOptions;\n\n    /**\n     * <p>Subclasses must implement this method to reduce\n     * the <code>arguments</code> that have been passed to the parse\n     * method.</p>\n     *\n     * @param opts            The Options to parse the arguments by.\n     * @param arguments            The arguments that have to be flattened.\n     * @param stopAtNonOption specifies whether to stop\n     *                        flattening when a non option has been encountered\n     * @return a String array of the flattened arguments\n     */\n    abstract protected String[] flatten(Options opts,\n                                        String[] arguments,\n                                        boolean stopAtNonOption);\n\n    /**\n     * <p>Parses the specified <code>arguments</code>\n     * based on the specifed {@link Options}.</p>\n     *\n     * @param options   the <code>Options</code>\n     * @param arguments the <code>arguments</code>\n     * @return the <code>CommandLine</code>\n     * @throws ParseException if an error occurs when parsing the\n     *                        arguments.\n     */\n    public CommandLine parse(Options options, String[] arguments)\n            throws ParseException {\n        return parse(options, arguments, false);\n    }\n\n    /**\n     * <p>Parses the specified <code>arguments</code>\n     * based on the specifed {@link Options}.</p>\n     *\n     * @param opts         the <code>Options</code>\n     * @param arguments       the <code>arguments</code>\n     * @param stopAtNonOption specifies whether to stop\n     *                        interpreting the arguments when a non option has\n     *                        been encountered and to add them to the CommandLines\n     *                        args list.\n     * @return the <code>CommandLine</code>\n     * @throws ParseException if an error occurs when parsing the\n     *                        arguments.\n     */\n    public CommandLine parse(Options opts,\n                             String[] arguments,\n                             boolean stopAtNonOption)\n            throws ParseException {\n        // initialise members\n        options = opts;\n        requiredOptions = options.getRequiredOptions();\n        cmd = new CommandLine();\n\n        boolean eatTheRest = false;\n\n        List tokenList = Arrays.asList(flatten(opts, arguments, stopAtNonOption));\n        ListIterator iterator = tokenList.listIterator();\n\n        // process each flattened token\n        while (iterator.hasNext()) {\n            String t = (String) iterator.next();\n\n            // the value is the double-dash\n            if (\"--\".equals(t)) {\n                eatTheRest = true;\n            }\n            // the value is a single dash\n            else if (\"-\".equals(t)) {\n                if (stopAtNonOption) {\n                    eatTheRest = true;\n                } else {\n                    cmd.addArg(t);\n                }\n            }\n            // the value is an option\n            else if (t.startsWith(\"-\")) {\n                if (stopAtNonOption && !options.hasOption(t)) {\n                    eatTheRest = true;\n                    cmd.addArg(t);\n                } else {\n                    processOption(t, iterator);\n                }\n            }\n            // the value is an argument\n            else {\n                cmd.addArg(t);\n                if (stopAtNonOption) {\n                    eatTheRest = true;\n                }\n            }\n\n            // eat the remaining tokens\n            if (eatTheRest) {\n                while (iterator.hasNext()) {\n                    String str = (String) iterator.next();\n                    // ensure only one double-dash is added\n                    if (!\"--\".equals(str)) {\n                        cmd.addArg(str);\n                    }\n                }\n            }\n        }\n        checkRequiredOptions();\n        return cmd;\n    }\n\n    /**\n     * <p>Throws a {@link MissingOptionException} if all of the\n     * required options are no present.</p>\n     */\n    private void checkRequiredOptions()\n            throws MissingOptionException {\n\n        // if there are required options that have not been\n        // processsed\n        if (requiredOptions.size() > 0) {\n            Iterator iter = requiredOptions.iterator();\n            StringBuffer buff = new StringBuffer();\n\n            // loop through the required options\n            while (iter.hasNext()) {\n                buff.append(iter.next());\n            }\n\n            throw new MissingOptionException(buff.toString());\n        }\n    }\n\n    public void processArgs(Option opt, ListIterator iter)\n            throws ParseException {\n        // loop until an option is found\n        while (iter.hasNext()) {\n            String var = (String) iter.next();\n\n            // found an Option\n            if (options.hasOption(var)) {\n                iter.previous();\n                break;\n            }\n            // found a value\n            else if (!opt.addValue(var)) {\n                iter.previous();\n                break;\n            }\n        }\n\n        if (opt.getValues() == null && !opt.hasOptionalArg()) {\n            throw new MissingArgumentException(\"no argument for:\" + opt.getOpt());\n        }\n    }\n\n    private void processOption(String arg, ListIterator iter)\n            throws ParseException {\n        // get the option represented by arg\n        Option opt = null;\n\n        boolean hasOption = options.hasOption(arg);\n\n        // if there is no option throw an UnrecognisedOptionException\n        if (!hasOption) {\n            throw new UnrecognizedOptionException(\"Unrecognized option: \" + arg);\n        } else {\n            opt = (Option) options.getOption(arg);\n        }\n\n        // if the option is a required option remove the option from\n        // the requiredOptions list\n        if (opt.isRequired()) {\n            requiredOptions.remove(\"-\" + opt.getOpt());\n        }\n\n        // if the option is in an OptionGroup make that option the selected\n        // option of the group\n        if (options.getOptionGroup(opt) != null) {\n            OptionGroup group = (OptionGroup) options.getOptionGroup(opt);\n            if (group.isRequired()) {\n                requiredOptions.remove(group);\n            }\n            group.setSelected(opt);\n        }\n\n        // if the option takes an argument value\n        if (opt.hasArg()) {\n            processArgs(opt, iter);\n        }\n\n        // set the option on the command line\n        cmd.addOption(opt);\n    }\n}"
  },
  {
    "path": "src/org/apache/commons/cli/PatternOptionBuilder.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/PatternOptionBuilder.java,v 1.2 2002/06/06 22:49:36 bayard Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 22:49:36 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * Allows Options to be created from a single String.\n *\n * @author Henri Yandell (bayard @ generationjava.com)\n * @version $Revision: 1.2 $\n */\npublic class PatternOptionBuilder {\n\n    /// TODO: These need to break out to OptionType and also to be pluggable.\n\n    /**\n     * String class\n     */\n    public static final Class STRING_VALUE = java.lang.String.class;\n    /**\n     * Object class\n     */\n    public static final Class OBJECT_VALUE = java.lang.Object.class;\n    /**\n     * Number class\n     */\n    public static final Class NUMBER_VALUE = java.lang.Number.class;\n    /**\n     * Date class\n     */\n    public static final Class DATE_VALUE = java.util.Date.class;\n    /**\n     * Class class\n     */\n    public static final Class CLASS_VALUE = java.lang.Class.class;\n\n/// can we do this one?? \n// is meant to check that the file exists, else it errors.\n// ie) it's for reading not writing.\n    /**\n     * FileInputStream class\n     */\n    public static final Class EXISTING_FILE_VALUE = java.io.FileInputStream.class;\n    /**\n     * File class\n     */\n    public static final Class FILE_VALUE = java.io.File.class;\n    /**\n     * File array class\n     */\n    public static final Class FILES_VALUE = java.io.File[].class;\n    /**\n     * URL class\n     */\n    public static final Class URL_VALUE = java.net.URL.class;\n\n    /**\n     * <p>Retrieve the class that <code>ch</code> represents.</p>\n     *\n     * @param ch the specified character\n     * @return The class that <code>ch</code> represents\n     */\n    public static Object getValueClass(char ch) {\n        if (ch == '@') {\n            return PatternOptionBuilder.OBJECT_VALUE;\n        } else if (ch == ':') {\n            return PatternOptionBuilder.STRING_VALUE;\n        } else if (ch == '%') {\n            return PatternOptionBuilder.NUMBER_VALUE;\n        } else if (ch == '+') {\n            return PatternOptionBuilder.CLASS_VALUE;\n        } else if (ch == '#') {\n            return PatternOptionBuilder.DATE_VALUE;\n        } else if (ch == '<') {\n            return PatternOptionBuilder.EXISTING_FILE_VALUE;\n        } else if (ch == '>') {\n            return PatternOptionBuilder.FILE_VALUE;\n        } else if (ch == '*') {\n            return PatternOptionBuilder.FILES_VALUE;\n        } else if (ch == '/') {\n            return PatternOptionBuilder.URL_VALUE;\n        }\n        return null;\n    }\n\n    /**\n     * <p>Returns whether <code>ch</code> is a value code, i.e.\n     * whether it represents a class in a pattern.</p>\n     *\n     * @param ch the specified character\n     * @return true if <code>ch</code> is a value code, otherwise false.\n     */\n    public static boolean isValueCode(char ch) {\n        if ((ch != '@') &&\n                (ch != ':') &&\n                (ch != '%') &&\n                (ch != '+') &&\n                (ch != '#') &&\n                (ch != '<') &&\n                (ch != '>') &&\n                (ch != '*') &&\n                (ch != '/')\n                ) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * <p>Returns the {@link Options} instance represented by\n     * <code>pattern</code>.</p>\n     *\n     * @param pattern the pattern string\n     * @return The {@link Options} instance\n     */\n    public static Options parsePattern(String pattern) {\n        int sz = pattern.length();\n\n        char opt = ' ';\n        char ch = ' ';\n        boolean required = false;\n        Object type = null;\n\n        Options options = new Options();\n\n        for (int i = 0; i < sz; i++) {\n            ch = pattern.charAt(i);\n\n            // a value code comes after an option and specifies \n            // details about it\n            if (!isValueCode(ch)) {\n                if (opt != ' ') {\n                    // we have a previous one to deal with\n                    options.addOption(OptionBuilder.hasArg(type != null)\n                            .isRequired(required)\n                            .withType(type)\n                            .create(opt));\n                    required = false;\n                    type = null;\n                    opt = ' ';\n                }\n                opt = ch;\n            } else if (ch == '!') {\n                required = true;\n            } else {\n                type = getValueClass(ch);\n            }\n        }\n\n        if (opt != ' ') {\n            // we have a final one to deal with\n            options.addOption(OptionBuilder.hasArg(type != null)\n                    .isRequired(required)\n                    .withType(type)\n                    .create(opt));\n        }\n\n        return options;\n    }\n\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/PosixParser.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons/cli/src/java/org/apache/commons/cli/PosixParser.java,v 1.11 2002/09/19 22:59:43 jkeyes Exp $\n * $Revision: 1.11 $\n * $Date: 2002/09/19 22:59:43 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\npackage org.apache.commons.cli;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Iterator;\n\n/**\n * The class PosixParser provides an implementation of the\n * {@link Parser#flatten(Options, String[], boolean) flatten} method.\n *\n * @author John Keyes (john at integralsource.com)\n * @version $Revision: 1.11 $\n * @see Parser\n */\npublic class PosixParser extends Parser {\n\n    /**\n     * holder for flattened tokens\n     */\n    private ArrayList tokens = new ArrayList();\n    /**\n     * specifies if bursting should continue\n     */\n    private boolean eatTheRest;\n    /**\n     * holder for the current option\n     */\n    private Option currentOption;\n    /**\n     * the command line Options\n     */\n    private Options options;\n\n    /**\n     * <p>Resets the members to their original state i.e. remove\n     * all of <code>tokens</code> entries, set <code>eatTheRest</code>\n     * to false and set <code>currentOption</code> to null.</p>\n     */\n    private void init() {\n        eatTheRest = false;\n        tokens.clear();\n        currentOption = null;\n    }\n\n    /**\n     * <p>An implementation of {@link Parser}'s abstract\n     * {@link Parser#flatten(Options, String[], boolean) flatten} method.</p>\n     * <p>\n     * <p>The following are the rules used by this flatten method.\n     * <ol>\n     * <li>if <code>stopAtNonOption</code> is <b>true</b> then do not\n     * burst anymore of <code>arguments</code> entries, just add each\n     * successive entry without further processing.  Otherwise, ignore\n     * <code>stopAtNonOption</code>.</li>\n     * <li>if the current <code>arguments</code> entry is \"<b>--</b>\"\n     * just add the entry to the list of processed tokens</li>\n     * <li>if the current <code>arguments</code> entry is \"<b>-</b>\"\n     * just add the entry to the list of processed tokens</li>\n     * <li>if the current <code>arguments</code> entry is two characters\n     * in length and the first character is \"<b>-</b>\" then check if this\n     * is a valid {@link Option} id.  If it is a valid id, then add the\n     * entry to the list of processed tokens and set the current {@link Option}\n     * member.  If it is not a valid id and <code>stopAtNonOption</code>\n     * is true, then the remaining entries are copied to the list of\n     * processed tokens.  Otherwise, the current entry is ignored.</li>\n     * <li>if the current <code>arguments</code> entry is more than two\n     * characters in length and the first character is \"<b>-</b>\" then\n     * we need to burst the entry to determine its constituents.  For more\n     * information on the bursting algorithm see\n     * {@link PosixParser#burstToken(String, boolean) burstToken}.</li>\n     * <li>if the current <code>arguments</code> entry is not handled\n     * by any of the previous rules, then the entry is added to the list\n     * of processed tokens.</li>\n     * </ol>\n     * </p>\n     *\n     * @param options         The command line {@link Options}\n     * @param arguments       The command line arguments to be parsed\n     * @param stopAtNonOption Specifies whether to stop flattening\n     *                        when an non option is found.\n     * @return The flattened <code>arguments</code> String array.\n     */\n    protected String[] flatten(Options options,\n                               String[] arguments,\n                               boolean stopAtNonOption) {\n        init();\n        this.options = options;\n\n        // an iterator for the command line tokens\n        Iterator iter = Arrays.asList(arguments).iterator();\n        String token = null;\n\n        // process each command line token\n        while (iter.hasNext()) {\n\n            // get the next command line token\n            token = (String) iter.next();\n\n            // handle SPECIAL TOKEN\n            if (token.startsWith(\"--\")) {\n                if (token.indexOf('=') != -1) {\n                    tokens.add(token.substring(0, token.indexOf('=')));\n                    tokens.add(token.substring(token.indexOf('=') + 1,\n                            token.length()));\n                } else {\n                    tokens.add(token);\n                }\n            }\n            // single hyphen\n            else if (\"-\".equals(token)) {\n                processSingleHyphen(token);\n            } else if (token.startsWith(\"-\")) {\n                int tokenLength = token.length();\n                if (tokenLength == 2) {\n                    processOptionToken(token, stopAtNonOption);\n                }\n                // requires bursting\n                else {\n                    burstToken(token, stopAtNonOption);\n                }\n            } else {\n                if (stopAtNonOption) {\n                    process(token);\n                } else {\n                    tokens.add(token);\n                }\n            }\n\n            gobble(iter);\n        }\n\n        return (String[]) tokens.toArray(new String[]{});\n    }\n\n    /**\n     * <p>Adds the remaining tokens to the processed tokens list.</p>\n     *\n     * @param iter An iterator over the remaining tokens\n     */\n    private void gobble(Iterator iter) {\n        if (eatTheRest) {\n            while (iter.hasNext()) {\n                tokens.add(iter.next());\n            }\n        }\n    }\n\n    /**\n     * <p>If there is a current option and it can have an argument\n     * value then add the token to the processed tokens list and\n     * set the current option to null.</p>\n     * <p>If there is a current option and it can have argument\n     * values then add the token to the processed tokens list.</p>\n     * <p>If there is not a current option add the special token\n     * \"<b>--</b>\" and the current <code>value</code> to the processed\n     * tokens list.  The add all the remaining <code>argument</code>\n     * values to the processed tokens list.</p>\n     *\n     * @param value The current token\n     */\n    private void process(String value) {\n        if (currentOption != null && currentOption.hasArg()) {\n            if (currentOption.hasArg()) {\n                tokens.add(value);\n                currentOption = null;\n            } else if (currentOption.hasArgs()) {\n                tokens.add(value);\n            }\n        } else {\n            eatTheRest = true;\n            tokens.add(\"--\");\n            tokens.add(value);\n        }\n    }\n\n    /**\n     * <p>If it is a hyphen then add the hyphen directly to\n     * the processed tokens list.</p>\n     *\n     * @param hyphen The hyphen token\n     */\n    private void processSingleHyphen(String hyphen) {\n        tokens.add(hyphen);\n    }\n\n    /**\n     * <p>If an {@link Option} exists for <code>token</code> then\n     * set the current option and add the token to the processed\n     * list.</p>\n     * <p>If an {@link Option} does not exist and <code>stopAtNonOption</code>\n     * is set then ignore the current token and add the remaining tokens\n     * to the processed tokens list directly.</p>\n     *\n     * @param token           The current option token\n     * @param stopAtNonOption Specifies whether flattening should halt\n     *                        at the first non option.\n     */\n    private void processOptionToken(String token, boolean stopAtNonOption) {\n        if (this.options.hasOption(token)) {\n            currentOption = this.options.getOption(token);\n            tokens.add(token);\n        } else if (stopAtNonOption) {\n            eatTheRest = true;\n        }\n    }\n\n    /**\n     * <p>Breaks <code>token</code> into its constituent parts\n     * using the following algorithm.\n     * <ul>\n     * <li>ignore the first character (\"<b>-</b>\" )</li>\n     * <li>foreach remaining character check if an {@link Option}\n     * exists with that id.</li>\n     * <li>if an {@link Option} does exist then add that character\n     * prepended with \"<b>-</b>\" to the list of processed tokens.</li>\n     * <li>if the {@link Option} can have an argument value and there\n     * are remaining characters in the token then add the remaining\n     * characters as a token to the list of processed tokens.</li>\n     * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>\n     * <code>stopAtNonOption</code> <b>IS</b> set then add the special token\n     * \"<b>--</b>\" followed by the remaining characters and also\n     * the remaining tokens directly to the processed tokens list.</li>\n     * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b>\n     * <code>stopAtNonOption</code> <b>IS NOT</b> set then add that\n     * character prepended with \"<b>-</b>\".</li>\n     * </ul>\n     * </p>\n     */\n    protected void burstToken(String token, boolean stopAtNonOption) {\n        int tokenLength = token.length();\n\n        for (int i = 1; i < tokenLength; i++) {\n            String ch = String.valueOf(token.charAt(i));\n            boolean hasOption = options.hasOption(ch);\n\n            if (hasOption) {\n                tokens.add(\"-\" + ch);\n                currentOption = options.getOption(ch);\n                if (currentOption.hasArg() && token.length() != i + 1) {\n                    tokens.add(token.substring(i + 1));\n                    break;\n                }\n            } else if (stopAtNonOption) {\n                process(token.substring(i));\n            } else {\n                tokens.add(\"-\" + ch);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/org/apache/commons/cli/TypeHandler.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/TypeHandler.java,v 1.2 2002/06/06 22:49:36 bayard Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 22:49:36 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\nimport org.apache.commons.lang.math.NumberUtils;\n\nimport java.io.File;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.Date;\n\n/**\n * This is a temporary implementation. TypeHandler will handle the\n * pluggableness of OptionTypes and it will direct all of these types\n * of conversion functionalities to ConvertUtils component in Commons\n * alreayd. BeanUtils I think.\n *\n * @author Henri Yandell (bayard @ generationjava.com)\n * @version $Revision: 1.2 $\n */\npublic class TypeHandler {\n\n    /**\n     * <p>Returns the <code>Object</code> of type <code>obj</code>\n     * with the value of <code>str</code>.</p>\n     *\n     * @param str the command line value\n     * @param obj the type of argument\n     * @return The instance of <code>obj</code> initialised with\n     * the value of <code>str</code>.\n     */\n    public static Object createValue(String str, Object obj) {\n        return createValue(str, (Class) obj);\n    }\n\n    /**\n     * <p>Returns the <code>Object</code> of type <code>clazz</code>\n     * with the value of <code>str</code>.</p>\n     *\n     * @param str   the command line value\n     * @param clazz the type of argument\n     * @return The instance of <code>clazz</code> initialised with\n     * the value of <code>str</code>.\n     */\n    public static Object createValue(String str, Class clazz) {\n        if (PatternOptionBuilder.STRING_VALUE == clazz) {\n            return str;\n        } else if (PatternOptionBuilder.OBJECT_VALUE == clazz) {\n            return createObject(str);\n        } else if (PatternOptionBuilder.NUMBER_VALUE == clazz) {\n            return createNumber(str);\n        } else if (PatternOptionBuilder.DATE_VALUE == clazz) {\n            return createDate(str);\n        } else if (PatternOptionBuilder.CLASS_VALUE == clazz) {\n            return createClass(str);\n        } else if (PatternOptionBuilder.FILE_VALUE == clazz) {\n            return createFile(str);\n        } else if (PatternOptionBuilder.EXISTING_FILE_VALUE == clazz) {\n            return createFile(str);\n        } else if (PatternOptionBuilder.FILES_VALUE == clazz) {\n            return createFiles(str);\n        } else if (PatternOptionBuilder.URL_VALUE == clazz) {\n            return createURL(str);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * <p>Create an Object from the classname and empty constructor.</p>\n     *\n     * @param str the argument value\n     * @return the initialised object, or null if it couldn't create the Object.\n     */\n    public static Object createObject(String str) {\n        Class cl = null;\n        try {\n            cl = Class.forName(str);\n        } catch (ClassNotFoundException cnfe) {\n            System.err.println(\"Unable to find: \" + str);\n            return null;\n        }\n\n        Object instance = null;\n\n        try {\n            instance = cl.newInstance();\n        } catch (InstantiationException cnfe) {\n            System.err.println(\"InstantiationException; Unable to create: \" + str);\n            return null;\n        } catch (IllegalAccessException cnfe) {\n            System.err.println(\"IllegalAccessException; Unable to create: \" + str);\n            return null;\n        }\n\n        return instance;\n    }\n\n    /**\n     * <p>Create a number from a String.</p>\n     *\n     * @param str the value\n     * @return the number represented by <code>str</code>, if <code>str</code>\n     * is not a number, null is returned.\n     */\n    public static Number createNumber(String str) {\n        // Needs to be able to create\n        try {\n            // do searching for decimal point etc, but atm just make an Integer\n            return NumberUtils.createNumber(str);\n        } catch (NumberFormatException nfe) {\n            System.err.println(nfe.getMessage());\n            return null;\n        }\n    }\n\n    /**\n     * <p>Returns the class whose name is <code>str</code>.</p>\n     *\n     * @param str the class name\n     * @return The class if it is found, otherwise return null\n     */\n    public static Class createClass(String str) {\n        try {\n            return Class.forName(str);\n        } catch (ClassNotFoundException cnfe) {\n            System.err.println(\"Unable to find: \" + str);\n            return null;\n        }\n    }\n\n    /**\n     * <p>Returns the date represented by <code>str</code>.</p>\n     *\n     * @param str the date string\n     * @return The date if <code>str</code> is a valid date string,\n     * otherwise return null.\n     */\n    public static Date createDate(String str) {\n        Date date = null;\n        if (date == null) {\n            System.err.println(\"Unable to parse: \" + str);\n        }\n        return date;\n    }\n\n    /**\n     * <p>Returns the URL represented by <code>str</code>.</p>\n     *\n     * @param str the URL string\n     * @return The URL is <code>str</code> is well-formed, otherwise\n     * return null.\n     */\n    public static URL createURL(String str) {\n        try {\n            return new URL(str);\n        } catch (MalformedURLException mue) {\n            System.err.println(\"Unable to parse: \" + str);\n            return null;\n        }\n    }\n\n    /**\n     * <p>Returns the File represented by <code>str</code>.</p>\n     *\n     * @param str the File location\n     * @return The file represented by <code>str</code>.\n     */\n    public static File createFile(String str) {\n        return new File(str);\n    }\n\n    /**\n     * <p>Returns the File[] represented by <code>str</code>.</p>\n     *\n     * @param str the paths to the files\n     * @return The File[] represented by <code>str</code>.\n     */\n    public static File[] createFiles(String str) {\n// to implement/port:\n//        return FileW.findFiles(str);\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/UnrecognizedOptionException.java",
    "content": "/*\n * $Header: /home/cvs/jakarta-commons-sandbox/cli/src/java/org/apache/commons/cli/UnrecognizedOptionException.java,v 1.2 2002/06/06 09:37:26 jstrachan Exp $\n * $Revision: 1.2 $\n * $Date: 2002/06/06 09:37:26 $\n *\n * ====================================================================\n *\n * The Apache Software License, Version 1.1\n *\n * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights\n * reserved.\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions\n * are met:\n *\n * 1. Redistributions of source code must retain the above copyright\n *    notice, this list of conditions and the following disclaimer.\n *\n * 2. Redistributions in binary form must reproduce the above copyright\n *    notice, this list of conditions and the following disclaimer in\n *    the documentation and/or other materials provided with the\n *    distribution.\n *\n * 3. The end-user documentation included with the redistribution, if\n *    any, must include the following acknowlegement:\n *       \"This product includes software developed by the\n *        Apache Software Foundation (http://www.apache.org/).\"\n *    Alternately, this acknowlegement may appear in the software itself,\n *    if and wherever such third-party acknowlegements normally appear.\n *\n * 4. The names \"The Jakarta Project\", \"Commons\", and \"Apache Software\n *    Foundation\" must not be used to endorse or promote products derived\n *    from this software without prior written permission. For written\n *    permission, please contact apache@apache.org.\n *\n * 5. Products derived from this software may not be called \"Apache\"\n *    nor may \"Apache\" appear in their names without prior written\n *    permission of the Apache Group.\n *\n * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED\n * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR\n * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF\n * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\n * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n * ====================================================================\n *\n * This software consists of voluntary contributions made by many\n * individuals on behalf of the Apache Software Foundation.  For more\n * information on the Apache Software Foundation, please see\n * <http://www.apache.org/>.\n *\n */\n\npackage org.apache.commons.cli;\n\n/**\n * <p>Exception thrown during parsing signalling an unrecognized\n * option was seen.<p>\n *\n * @author bob mcwhiter (bob @ werken.com)\n * @version $Revision: 1.2 $\n */\npublic class UnrecognizedOptionException extends ParseException {\n\n    /**\n     * <p>Construct a new <code>UnrecognizedArgumentException</code>\n     * with the specified detail message.</p>\n     *\n     * @param message the detail message\n     */\n    public UnrecognizedOptionException(String message) {\n        super(message);\n    }\n}\n"
  },
  {
    "path": "src/org/apache/commons/cli/overview.html",
    "content": "<body>\n\n<p>Commons CLI -- version ##VERSION## (##QUALITY##)</p>\n\n<p>The commons-cli package aides in parsing command-line arguments.</p>\n\n<p>Allow command-line arguments to be parsed against a descriptor of\n    valid options (long and short), potentially with arguments.</p>\n\n<p>command-line arguments may be of the typical <code>String[]</code>\n    form, but also may be a <code>java.util.List</code>. Indexes allow\n    for parsing only a portion of the command-line. Also, functionality\n    for parsing the command-line in phases is built in, allowing for\n    'cvs-style' command-lines, where some global options are specified\n    before a 'command' argument, and command-specific options are\n    specified after the command argument:\n\n    <code>\n\t<pre>\n\t\tmyApp -p &lt;port&gt; command -p &lt;printer&gt;\n\t</pre>\n    </code>\n\n\n<p>The homepage for the project is\n    <a href=\"http://jakarta.apache.org/commons/\">jakarta commons/</a>\n</body>\n"
  },
  {
    "path": "src/org/apache/commons/cli/package.html",
    "content": "<body>\n\n<p>Commons CLI 1.0</p>\n\n</body>\n"
  },
  {
    "path": "src/org/apache/commons/lang/math/NumberUtils.java",
    "content": "/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreements.  See the NOTICE file distributed with\n * this work for additional information regarding copyright ownership.\n * The ASF licenses this file to You under the Apache License, Version 2.0\n * (the \"License\"); you may not use this file except in compliance with\n * the License.  You may obtain a copy of the License at\n * \n *      http://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage org.apache.commons.lang.math;\n\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\n\n/**\n * <p>Provides extra functionality for Java Number classes.</p>\n *\n * @author <a href=\"mailto:bayard@generationjava.com\">Henri Yandell</a>\n * @author <a href=\"mailto:rand_mcneely@yahoo.com\">Rand McNeely</a>\n * @author Stephen Colebourne\n * @author <a href=\"mailto:steve.downey@netfolio.com\">Steve Downey</a>\n * @author Eric Pugh\n * @author Phil Steitz\n * @author Matthew Hawthorne\n * @author <a href=\"mailto:ggregory@seagullsw.com\">Gary Gregory</a>\n * @author <a href=\"mailto:fredrik@westermarck.com\">Fredrik Westermarck</a>\n * @version $Id: NumberUtils.java 437554 2006-08-28 06:21:41Z bayard $\n * @since 2.0\n */\npublic class NumberUtils {\n\n    /**\n     * Reusable Long constant for zero.\n     */\n    public static final Long LONG_ZERO = new Long(0L);\n    /**\n     * Reusable Long constant for one.\n     */\n    public static final Long LONG_ONE = new Long(1L);\n    /**\n     * Reusable Long constant for minus one.\n     */\n    public static final Long LONG_MINUS_ONE = new Long(-1L);\n    /**\n     * Reusable Integer constant for zero.\n     */\n    public static final Integer INTEGER_ZERO = new Integer(0);\n    /**\n     * Reusable Integer constant for one.\n     */\n    public static final Integer INTEGER_ONE = new Integer(1);\n    /**\n     * Reusable Integer constant for minus one.\n     */\n    public static final Integer INTEGER_MINUS_ONE = new Integer(-1);\n    /**\n     * Reusable Short constant for zero.\n     */\n    public static final Short SHORT_ZERO = new Short((short) 0);\n    /**\n     * Reusable Short constant for one.\n     */\n    public static final Short SHORT_ONE = new Short((short) 1);\n    /**\n     * Reusable Short constant for minus one.\n     */\n    public static final Short SHORT_MINUS_ONE = new Short((short) -1);\n    /**\n     * Reusable Byte constant for zero.\n     */\n    public static final Byte BYTE_ZERO = new Byte((byte) 0);\n    /**\n     * Reusable Byte constant for one.\n     */\n    public static final Byte BYTE_ONE = new Byte((byte) 1);\n    /**\n     * Reusable Byte constant for minus one.\n     */\n    public static final Byte BYTE_MINUS_ONE = new Byte((byte) -1);\n    /**\n     * Reusable Double constant for zero.\n     */\n    public static final Double DOUBLE_ZERO = new Double(0.0d);\n    /**\n     * Reusable Double constant for one.\n     */\n    public static final Double DOUBLE_ONE = new Double(1.0d);\n    /**\n     * Reusable Double constant for minus one.\n     */\n    public static final Double DOUBLE_MINUS_ONE = new Double(-1.0d);\n    /**\n     * Reusable Float constant for zero.\n     */\n    public static final Float FLOAT_ZERO = new Float(0.0f);\n    /**\n     * Reusable Float constant for one.\n     */\n    public static final Float FLOAT_ONE = new Float(1.0f);\n    /**\n     * Reusable Float constant for minus one.\n     */\n    public static final Float FLOAT_MINUS_ONE = new Float(-1.0f);\n\n    /**\n     * <p><code>NumberUtils</code> instances should NOT be constructed in standard programming.\n     * Instead, the class should be used as <code>NumberUtils.stringToInt(\"6\");</code>.</p>\n     * <p>\n     * <p>This constructor is public to permit tools that require a JavaBean instance\n     * to operate.</p>\n     */\n    public NumberUtils() {\n        super();\n    }\n\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Convert a <code>String</code> to an <code>int</code>, returning\n     * <code>zero</code> if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.stringToInt(null) = 0\n     *   NumberUtils.stringToInt(\"\")   = 0\n     *   NumberUtils.stringToInt(\"1\")  = 1\n     * </pre>\n     *\n     * @param str the string to convert, may be null\n     * @return the int represented by the string, or <code>zero</code> if\n     * conversion fails\n     * @deprecated Use {@link #toInt(String)}\n     * This method will be removed in Commons Lang 3.0\n     */\n    public static int stringToInt(String str) {\n        return toInt(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to an <code>int</code>, returning\n     * <code>zero</code> if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toInt(null) = 0\n     *   NumberUtils.toInt(\"\")   = 0\n     *   NumberUtils.toInt(\"1\")  = 1\n     * </pre>\n     *\n     * @param str the string to convert, may be null\n     * @return the int represented by the string, or <code>zero</code> if\n     * conversion fails\n     * @since 2.1\n     */\n    public static int toInt(String str) {\n        return toInt(str, 0);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to an <code>int</code>, returning a\n     * default value if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, the default value is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.stringToInt(null, 1) = 1\n     *   NumberUtils.stringToInt(\"\", 1)   = 1\n     *   NumberUtils.stringToInt(\"1\", 0)  = 1\n     * </pre>\n     *\n     * @param str          the string to convert, may be null\n     * @param defaultValue the default value\n     * @return the int represented by the string, or the default if conversion fails\n     * @deprecated Use {@link #toInt(String, int)}\n     * This method will be removed in Commons Lang 3.0\n     */\n    public static int stringToInt(String str, int defaultValue) {\n        return toInt(str, defaultValue);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to an <code>int</code>, returning a\n     * default value if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, the default value is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toInt(null, 1) = 1\n     *   NumberUtils.toInt(\"\", 1)   = 1\n     *   NumberUtils.toInt(\"1\", 0)  = 1\n     * </pre>\n     *\n     * @param str          the string to convert, may be null\n     * @param defaultValue the default value\n     * @return the int represented by the string, or the default if conversion fails\n     * @since 2.1\n     */\n    public static int toInt(String str, int defaultValue) {\n        if (str == null) {\n            return defaultValue;\n        }\n        try {\n            return Integer.parseInt(str);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>long</code>, returning\n     * <code>zero</code> if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, <code>zero</code> is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toLong(null) = 0L\n     *   NumberUtils.toLong(\"\")   = 0L\n     *   NumberUtils.toLong(\"1\")  = 1L\n     * </pre>\n     *\n     * @param str the string to convert, may be null\n     * @return the long represented by the string, or <code>0</code> if\n     * conversion fails\n     * @since 2.1\n     */\n    public static long toLong(String str) {\n        return toLong(str, 0L);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>long</code>, returning a\n     * default value if the conversion fails.</p>\n     * <p>\n     * <p>If the string is <code>null</code>, the default value is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toLong(null, 1L) = 1L\n     *   NumberUtils.toLong(\"\", 1L)   = 1L\n     *   NumberUtils.toLong(\"1\", 0L)  = 1L\n     * </pre>\n     *\n     * @param str          the string to convert, may be null\n     * @param defaultValue the default value\n     * @return the long represented by the string, or the default if conversion fails\n     * @since 2.1\n     */\n    public static long toLong(String str, long defaultValue) {\n        if (str == null) {\n            return defaultValue;\n        }\n        try {\n            return Long.parseLong(str);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>float</code>, returning\n     * <code>0.0f</code> if the conversion fails.</p>\n     * <p>\n     * <p>If the string <code>str</code> is <code>null</code>,\n     * <code>0.0f</code> is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toFloat(null)   = 0.0f\n     *   NumberUtils.toFloat(\"\")     = 0.0f\n     *   NumberUtils.toFloat(\"1.5\")  = 1.5f\n     * </pre>\n     *\n     * @param str the string to convert, may be <code>null</code>\n     * @return the float represented by the string, or <code>0.0f</code>\n     * if conversion fails\n     * @since 2.1\n     */\n    public static float toFloat(String str) {\n        return toFloat(str, 0.0f);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>float</code>, returning a\n     * default value if the conversion fails.</p>\n     * <p>\n     * <p>If the string <code>str</code> is <code>null</code>, the default\n     * value is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toFloat(null, 1.1f)   = 1.0f\n     *   NumberUtils.toFloat(\"\", 1.1f)     = 1.1f\n     *   NumberUtils.toFloat(\"1.5\", 0.0f)  = 1.5f\n     * </pre>\n     *\n     * @param str          the string to convert, may be <code>null</code>\n     * @param defaultValue the default value\n     * @return the float represented by the string, or defaultValue\n     * if conversion fails\n     * @since 2.1\n     */\n    public static float toFloat(String str, float defaultValue) {\n        if (str == null) {\n            return defaultValue;\n        }\n        try {\n            return Float.parseFloat(str);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>double</code>, returning\n     * <code>0.0d</code> if the conversion fails.</p>\n     * <p>\n     * <p>If the string <code>str</code> is <code>null</code>,\n     * <code>0.0d</code> is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toDouble(null)   = 0.0d\n     *   NumberUtils.toDouble(\"\")     = 0.0d\n     *   NumberUtils.toDouble(\"1.5\")  = 1.5d\n     * </pre>\n     *\n     * @param str the string to convert, may be <code>null</code>\n     * @return the double represented by the string, or <code>0.0d</code>\n     * if conversion fails\n     * @since 2.1\n     */\n    public static double toDouble(String str) {\n        return toDouble(str, 0.0d);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>double</code>, returning a\n     * default value if the conversion fails.</p>\n     * <p>\n     * <p>If the string <code>str</code> is <code>null</code>, the default\n     * value is returned.</p>\n     * <p>\n     * <pre>\n     *   NumberUtils.toDouble(null, 1.1d)   = 1.1d\n     *   NumberUtils.toDouble(\"\", 1.1d)     = 1.1d\n     *   NumberUtils.toDouble(\"1.5\", 0.0d)  = 1.5d\n     * </pre>\n     *\n     * @param str          the string to convert, may be <code>null</code>\n     * @param defaultValue the default value\n     * @return the double represented by the string, or defaultValue\n     * if conversion fails\n     * @since 2.1\n     */\n    public static double toDouble(String str, double defaultValue) {\n        if (str == null) {\n            return defaultValue;\n        }\n        try {\n            return Double.parseDouble(str);\n        } catch (NumberFormatException nfe) {\n            return defaultValue;\n        }\n    }\n\n    //-----------------------------------------------------------------------\n    // must handle Long, Float, Integer, Float, Short,\n    //                  BigDecimal, BigInteger and Byte\n    // useful methods:\n    // Byte.decode(String)\n    // Byte.valueOf(String,int radix)\n    // Byte.valueOf(String)\n    // Double.valueOf(String)\n    // Float.valueOf(String)\n    // new Float(String)\n    // Integer.valueOf(String,int radix)\n    // Integer.valueOf(String)\n    // Integer.decode(String)\n    // Integer.getInteger(String)\n    // Integer.getInteger(String,int val)\n    // Integer.getInteger(String,Integer val)\n    // new Integer(String)\n    // new Double(String)\n    // new Byte(String)\n    // new Long(String)\n    // Long.getLong(String)\n    // Long.getLong(String,int)\n    // Long.getLong(String,Integer)\n    // Long.valueOf(String,int)\n    // Long.valueOf(String)\n    // new Short(String)\n    // Short.decode(String)\n    // Short.valueOf(String,int)\n    // Short.valueOf(String)\n    // new BigDecimal(String)\n    // new BigInteger(String)\n    // new BigInteger(String,int radix)\n    // Possible inputs:\n    // 45 45.5 45E7 4.5E7 Hex Oct Binary xxxF xxxD xxxf xxxd\n    // plus minus everything. Prolly more. A lot are not separable.\n\n    /**\n     * <p>Turns a string value into a java.lang.Number.</p>\n     * <p>\n     * <p>First, the value is examined for a type qualifier on the end\n     * (<code>'f','F','d','D','l','L'</code>).  If it is found, it starts\n     * trying to create successively larger types from the type specified\n     * until one is found that can represent the value.</p>\n     * <p>\n     * <p>If a type specifier is not found, it will check for a decimal point\n     * and then try successively larger types from <code>Integer</code> to\n     * <code>BigInteger</code> and from <code>Float</code> to\n     * <code>BigDecimal</code>.</p>\n     * <p>\n     * <p>If the string starts with <code>0x</code> or <code>-0x</code>, it\n     * will be interpreted as a hexadecimal integer.  Values with leading\n     * <code>0</code>'s will not be interpreted as octal.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     * <p>\n     * <p>This method does not trim the input string, i.e., strings with leading\n     * or trailing spaces will generate NumberFormatExceptions.</p>\n     *\n     * @param str String containing a number, may be null\n     * @return Number created from the string\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static Number createNumber(String str) throws NumberFormatException {\n        if (str == null) {\n            return null;\n        }\n        if (str == null || str.trim().length() == 0) {\n            throw new NumberFormatException(\"A blank string is not a valid number\");\n        }\n        if (str.startsWith(\"--\")) {\n            // this is protection for poorness in java.lang.BigDecimal.\n            // it accepts this as a legal value, but it does not appear \n            // to be in specification of class. OS X Java parses it to \n            // a wrong value.\n            return null;\n        }\n        if (str.startsWith(\"0x\") || str.startsWith(\"-0x\")) {\n            return createInteger(str);\n        }\n        char lastChar = str.charAt(str.length() - 1);\n        String mant;\n        String dec;\n        String exp;\n        int decPos = str.indexOf('.');\n        int expPos = str.indexOf('e') + str.indexOf('E') + 1;\n\n        if (decPos > -1) {\n\n            if (expPos > -1) {\n                if (expPos < decPos) {\n                    throw new NumberFormatException(str + \" is not a valid number.\");\n                }\n                dec = str.substring(decPos + 1, expPos);\n            } else {\n                dec = str.substring(decPos + 1);\n            }\n            mant = str.substring(0, decPos);\n        } else {\n            if (expPos > -1) {\n                mant = str.substring(0, expPos);\n            } else {\n                mant = str;\n            }\n            dec = null;\n        }\n        if (!Character.isDigit(lastChar)) {\n            if (expPos > -1 && expPos < str.length() - 1) {\n                exp = str.substring(expPos + 1, str.length() - 1);\n            } else {\n                exp = null;\n            }\n            //Requesting a specific type..\n            String numeric = str.substring(0, str.length() - 1);\n            boolean allZeros = isAllZeros(mant) && isAllZeros(exp);\n            switch (lastChar) {\n                case 'l':\n                case 'L':\n                    if (dec == null\n                            && exp == null\n                            && isDigits(numeric.substring(1))\n                            && (numeric.charAt(0) == '-' || Character.isDigit(numeric.charAt(0)))) {\n                        try {\n                            return createLong(numeric);\n                        } catch (NumberFormatException nfe) {\n                            //Too big for a long\n                        }\n                        return createBigInteger(numeric);\n\n                    }\n                    throw new NumberFormatException(str + \" is not a valid number.\");\n                case 'f':\n                case 'F':\n                    try {\n                        Float f = NumberUtils.createFloat(numeric);\n                        if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {\n                            //If it's too big for a float or the float value = 0 and the string\n                            //has non-zeros in it, then float does not have the precision we want\n                            return f;\n                        }\n\n                    } catch (NumberFormatException nfe) {\n                        // ignore the bad number\n                    }\n                    //Fall through\n                case 'd':\n                case 'D':\n                    try {\n                        Double d = NumberUtils.createDouble(numeric);\n                        if (!(d.isInfinite() || (d.floatValue() == 0.0D && !allZeros))) {\n                            return d;\n                        }\n                    } catch (NumberFormatException nfe) {\n                        // ignore the bad number\n                    }\n                    try {\n                        return createBigDecimal(numeric);\n                    } catch (NumberFormatException e) {\n                        // ignore the bad number\n                    }\n                    //Fall through\n                default:\n                    throw new NumberFormatException(str + \" is not a valid number.\");\n\n            }\n        } else {\n            //User doesn't have a preference on the return type, so let's start\n            //small and go from there...\n            if (expPos > -1 && expPos < str.length() - 1) {\n                exp = str.substring(expPos + 1, str.length());\n            } else {\n                exp = null;\n            }\n            if (dec == null && exp == null) {\n                //Must be an int,long,bigint\n                try {\n                    return createInteger(str);\n                } catch (NumberFormatException nfe) {\n                    // ignore the bad number\n                }\n                try {\n                    return createLong(str);\n                } catch (NumberFormatException nfe) {\n                    // ignore the bad number\n                }\n                return createBigInteger(str);\n\n            } else {\n                //Must be a float,double,BigDec\n                boolean allZeros = isAllZeros(mant) && isAllZeros(exp);\n                try {\n                    Float f = createFloat(str);\n                    if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) {\n                        return f;\n                    }\n                } catch (NumberFormatException nfe) {\n                    // ignore the bad number\n                }\n                try {\n                    Double d = createDouble(str);\n                    if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) {\n                        return d;\n                    }\n                } catch (NumberFormatException nfe) {\n                    // ignore the bad number\n                }\n\n                return createBigDecimal(str);\n\n            }\n        }\n    }\n\n    /**\n     * <p>Utility method for {@link #createNumber(java.lang.String)}.</p>\n     * <p>\n     * <p>Returns <code>true</code> if s is <code>null</code>.</p>\n     *\n     * @param str the String to check\n     * @return if it is all zeros or <code>null</code>\n     */\n    private static boolean isAllZeros(String str) {\n        if (str == null) {\n            return true;\n        }\n        for (int i = str.length() - 1; i >= 0; i--) {\n            if (str.charAt(i) != '0') {\n                return false;\n            }\n        }\n        return str.length() > 0;\n    }\n\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>Float</code>.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>Float</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static Float createFloat(String str) {\n        if (str == null) {\n            return null;\n        }\n        return Float.valueOf(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>Double</code>.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>Double</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static Double createDouble(String str) {\n        if (str == null) {\n            return null;\n        }\n        return Double.valueOf(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>Integer</code>, handling\n     * hex and octal notations.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>Integer</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static Integer createInteger(String str) {\n        if (str == null) {\n            return null;\n        }\n        // decode() handles 0xAABD and 0777 (hex and octal) as well.\n        return Integer.decode(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>Long</code>.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>Long</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static Long createLong(String str) {\n        if (str == null) {\n            return null;\n        }\n        return Long.valueOf(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>BigInteger</code>.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>BigInteger</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static BigInteger createBigInteger(String str) {\n        if (str == null) {\n            return null;\n        }\n        return new BigInteger(str);\n    }\n\n    /**\n     * <p>Convert a <code>String</code> to a <code>BigDecimal</code>.</p>\n     * <p>\n     * <p>Returns <code>null</code> if the string is <code>null</code>.</p>\n     *\n     * @param str a <code>String</code> to convert, may be null\n     * @return converted <code>BigDecimal</code>\n     * @throws NumberFormatException if the value cannot be converted\n     */\n    public static BigDecimal createBigDecimal(String str) {\n        if (str == null) {\n            return null;\n        }\n        // handle JDK1.3.1 bug where \"\" throws IndexOutOfBoundsException\n        if (str == null || str.trim().length() == 0) {\n            throw new NumberFormatException(\"A blank string is not a valid number\");\n        }\n        return new BigDecimal(str);\n    }\n\n    // Min in array\n    //--------------------------------------------------------------------\n\n    /**\n     * <p>Returns the minimum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static long min(long[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns min\n        long min = array[0];\n        for (int i = 1; i < array.length; i++) {\n            if (array[i] < min) {\n                min = array[i];\n            }\n        }\n\n        return min;\n    }\n\n    /**\n     * <p>Returns the minimum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static int min(int[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns min\n        int min = array[0];\n        for (int j = 1; j < array.length; j++) {\n            if (array[j] < min) {\n                min = array[j];\n            }\n        }\n\n        return min;\n    }\n\n    /**\n     * <p>Returns the minimum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static short min(short[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns min\n        short min = array[0];\n        for (int i = 1; i < array.length; i++) {\n            if (array[i] < min) {\n                min = array[i];\n            }\n        }\n\n        return min;\n    }\n\n    /**\n     * <p>Returns the minimum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static double min(double[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns min\n        double min = array[0];\n        for (int i = 1; i < array.length; i++) {\n            if (array[i] < min) {\n                min = array[i];\n            }\n        }\n\n        return min;\n    }\n\n    /**\n     * <p>Returns the minimum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static float min(float[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns min\n        float min = array[0];\n        for (int i = 1; i < array.length; i++) {\n            if (array[i] < min) {\n                min = array[i];\n            }\n        }\n\n        return min;\n    }\n\n    // Max in array\n    //--------------------------------------------------------------------\n\n    /**\n     * <p>Returns the maximum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static long max(long[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns max\n        long max = array[0];\n        for (int j = 1; j < array.length; j++) {\n            if (array[j] > max) {\n                max = array[j];\n            }\n        }\n\n        return max;\n    }\n\n    /**\n     * <p>Returns the maximum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static int max(int[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns max\n        int max = array[0];\n        for (int j = 1; j < array.length; j++) {\n            if (array[j] > max) {\n                max = array[j];\n            }\n        }\n\n        return max;\n    }\n\n    /**\n     * <p>Returns the maximum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static short max(short[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns max\n        short max = array[0];\n        for (int i = 1; i < array.length; i++) {\n            if (array[i] > max) {\n                max = array[i];\n            }\n        }\n\n        return max;\n    }\n\n    /**\n     * <p>Returns the maximum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static double max(double[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns max\n        double max = array[0];\n        for (int j = 1; j < array.length; j++) {\n            if (array[j] > max) {\n                max = array[j];\n            }\n        }\n\n        return max;\n    }\n\n    /**\n     * <p>Returns the maximum value in an array.</p>\n     *\n     * @param array an array, must not be null or empty\n     * @return the minimum value in the array\n     * @throws IllegalArgumentException if <code>array</code> is <code>null</code>\n     * @throws IllegalArgumentException if <code>array</code> is empty\n     */\n    public static float max(float[] array) {\n        // Validates input\n        if (array == null) {\n            throw new IllegalArgumentException(\"The Array must not be null\");\n        } else if (array.length == 0) {\n            throw new IllegalArgumentException(\"Array cannot be empty.\");\n        }\n\n        // Finds and returns max\n        float max = array[0];\n        for (int j = 1; j < array.length; j++) {\n            if (array[j] > max) {\n                max = array[j];\n            }\n        }\n\n        return max;\n    }\n\n    // 3 param min\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Gets the minimum of three <code>long</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static long min(long a, long b, long c) {\n        if (b < a) {\n            a = b;\n        }\n        if (c < a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the minimum of three <code>int</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static int min(int a, int b, int c) {\n        if (b < a) {\n            a = b;\n        }\n        if (c < a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the minimum of three <code>short</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static short min(short a, short b, short c) {\n        if (b < a) {\n            a = b;\n        }\n        if (c < a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the minimum of three <code>byte</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static byte min(byte a, byte b, byte c) {\n        if (b < a) {\n            a = b;\n        }\n        if (c < a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the minimum of three <code>double</code> values.</p>\n     * <p>\n     * <p>If any value is <code>NaN</code>, <code>NaN</code> is\n     * returned. Infinity is handled.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static double min(double a, double b, double c) {\n        return Math.min(Math.min(a, b), c);\n    }\n\n    /**\n     * <p>Gets the minimum of three <code>float</code> values.</p>\n     * <p>\n     * <p>If any value is <code>NaN</code>, <code>NaN</code> is\n     * returned. Infinity is handled.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the smallest of the values\n     */\n    public static float min(float a, float b, float c) {\n        return Math.min(Math.min(a, b), c);\n    }\n\n    // 3 param max\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Gets the maximum of three <code>long</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static long max(long a, long b, long c) {\n        if (b > a) {\n            a = b;\n        }\n        if (c > a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the maximum of three <code>int</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static int max(int a, int b, int c) {\n        if (b > a) {\n            a = b;\n        }\n        if (c > a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the maximum of three <code>short</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static short max(short a, short b, short c) {\n        if (b > a) {\n            a = b;\n        }\n        if (c > a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the maximum of three <code>byte</code> values.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static byte max(byte a, byte b, byte c) {\n        if (b > a) {\n            a = b;\n        }\n        if (c > a) {\n            a = c;\n        }\n        return a;\n    }\n\n    /**\n     * <p>Gets the maximum of three <code>double</code> values.</p>\n     * <p>\n     * <p>If any value is <code>NaN</code>, <code>NaN</code> is\n     * returned. Infinity is handled.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static double max(double a, double b, double c) {\n        return Math.max(Math.max(a, b), c);\n    }\n\n    /**\n     * <p>Gets the maximum of three <code>float</code> values.</p>\n     * <p>\n     * <p>If any value is <code>NaN</code>, <code>NaN</code> is\n     * returned. Infinity is handled.</p>\n     *\n     * @param a value 1\n     * @param b value 2\n     * @param c value 3\n     * @return the largest of the values\n     */\n    public static float max(float a, float b, float c) {\n        return Math.max(Math.max(a, b), c);\n    }\n\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Compares two <code>doubles</code> for order.</p>\n     * <p>\n     * <p>This method is more comprehensive than the standard Java greater\n     * than, less than and equals operators.</p>\n     * <ul>\n     * <li>It returns <code>-1</code> if the first value is less than the second.</li>\n     * <li>It returns <code>+1</code> if the first value is greater than the second.</li>\n     * <li>It returns <code>0</code> if the values are equal.</li>\n     * </ul>\n     * <p>\n     * <p>\n     * The ordering is as follows, largest to smallest:\n     * <ul>\n     * <li>NaN\n     * <li>Positive infinity\n     * <li>Maximum double\n     * <li>Normal positive numbers\n     * <li>+0.0\n     * <li>-0.0\n     * <li>Normal negative numbers\n     * <li>Minimum double (<code>-Double.MAX_VALUE</code>)\n     * <li>Negative infinity\n     * </ul>\n     * </p>\n     * <p>\n     * <p>Comparing <code>NaN</code> with <code>NaN</code> will\n     * return <code>0</code>.</p>\n     *\n     * @param lhs the first <code>double</code>\n     * @param rhs the second <code>double</code>\n     * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,\n     * <code>0</code> if equal to rhs\n     */\n    public static int compare(double lhs, double rhs) {\n        if (lhs < rhs) {\n            return -1;\n        }\n        if (lhs > rhs) {\n            return +1;\n        }\n        // Need to compare bits to handle 0.0 == -0.0 being true\n        // compare should put -0.0 < +0.0\n        // Two NaNs are also == for compare purposes\n        // where NaN == NaN is false\n        long lhsBits = Double.doubleToLongBits(lhs);\n        long rhsBits = Double.doubleToLongBits(rhs);\n        if (lhsBits == rhsBits) {\n            return 0;\n        }\n        // Something exotic! A comparison to NaN or 0.0 vs -0.0\n        // Fortunately NaN's long is > than everything else\n        // Also negzeros bits < poszero\n        // NAN: 9221120237041090560\n        // MAX: 9218868437227405311\n        // NEGZERO: -9223372036854775808\n        if (lhsBits < rhsBits) {\n            return -1;\n        } else {\n            return +1;\n        }\n    }\n\n    /**\n     * <p>Compares two floats for order.</p>\n     * <p>\n     * <p>This method is more comprehensive than the standard Java greater than,\n     * less than and equals operators.</p>\n     * <ul>\n     * <li>It returns <code>-1</code> if the first value is less than the second.\n     * <li>It returns <code>+1</code> if the first value is greater than the second.\n     * <li>It returns <code>0</code> if the values are equal.\n     * </ul>\n     * <p>\n     * <p> The ordering is as follows, largest to smallest:\n     * <ul>\n     * <li>NaN\n     * <li>Positive infinity\n     * <li>Maximum float\n     * <li>Normal positive numbers\n     * <li>+0.0\n     * <li>-0.0\n     * <li>Normal negative numbers\n     * <li>Minimum float (<code>-Float.MAX_VALUE</code>)\n     * <li>Negative infinity\n     * </ul>\n     * <p>\n     * <p>Comparing <code>NaN</code> with <code>NaN</code> will return\n     * <code>0</code>.</p>\n     *\n     * @param lhs the first <code>float</code>\n     * @param rhs the second <code>float</code>\n     * @return <code>-1</code> if lhs is less, <code>+1</code> if greater,\n     * <code>0</code> if equal to rhs\n     */\n    public static int compare(float lhs, float rhs) {\n        if (lhs < rhs) {\n            return -1;\n        }\n        if (lhs > rhs) {\n            return +1;\n        }\n        //Need to compare bits to handle 0.0 == -0.0 being true\n        // compare should put -0.0 < +0.0\n        // Two NaNs are also == for compare purposes\n        // where NaN == NaN is false\n        int lhsBits = Float.floatToIntBits(lhs);\n        int rhsBits = Float.floatToIntBits(rhs);\n        if (lhsBits == rhsBits) {\n            return 0;\n        }\n        //Something exotic! A comparison to NaN or 0.0 vs -0.0\n        //Fortunately NaN's int is > than everything else\n        //Also negzeros bits < poszero\n        //NAN: 2143289344\n        //MAX: 2139095039\n        //NEGZERO: -2147483648\n        if (lhsBits < rhsBits) {\n            return -1;\n        } else {\n            return +1;\n        }\n    }\n\n    //-----------------------------------------------------------------------\n\n    /**\n     * <p>Checks whether the <code>String</code> contains only\n     * digit characters.</p>\n     * <p>\n     * <p><code>Null</code> and empty String will return\n     * <code>false</code>.</p>\n     *\n     * @param str the <code>String</code> to check\n     * @return <code>true</code> if str contains only unicode numeric\n     */\n    public static boolean isDigits(String str) {\n        if (str == null || str.length() == 0) {\n            return false;\n        }\n        for (int i = 0; i < str.length(); i++) {\n            if (!Character.isDigit(str.charAt(i))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * <p>Checks whether the String a valid Java number.</p>\n     * <p>\n     * <p>Valid numbers include hexadecimal marked with the <code>0x</code>\n     * qualifier, scientific notation and numbers marked with a type\n     * qualifier (e.g. 123L).</p>\n     * <p>\n     * <p><code>Null</code> and empty String will return\n     * <code>false</code>.</p>\n     *\n     * @param str the <code>String</code> to check\n     * @return <code>true</code> if the string is a correctly formatted number\n     */\n    public static boolean isNumber(String str) {\n        if (str == null || str.length() == 0) {\n            return false;\n        }\n        char[] chars = str.toCharArray();\n        int sz = chars.length;\n        boolean hasExp = false;\n        boolean hasDecPoint = false;\n        boolean allowSigns = false;\n        boolean foundDigit = false;\n        // deal with any possible sign up front\n        int start = (chars[0] == '-') ? 1 : 0;\n        if (sz > start + 1) {\n            if (chars[start] == '0' && chars[start + 1] == 'x') {\n                int i = start + 2;\n                if (i == sz) {\n                    return false; // str == \"0x\"\n                }\n                // checking hex (it can't be anything else)\n                for (; i < chars.length; i++) {\n                    if ((chars[i] < '0' || chars[i] > '9')\n                            && (chars[i] < 'a' || chars[i] > 'f')\n                            && (chars[i] < 'A' || chars[i] > 'F')) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n        }\n        sz--; // don't want to loop to the last char, check it afterwords\n        // for type qualifiers\n        int i = start;\n        // loop to the next to last char or to the last char if we need another digit to\n        // make a valid number (e.g. chars[0..5] = \"1234E\")\n        while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {\n            if (chars[i] >= '0' && chars[i] <= '9') {\n                foundDigit = true;\n                allowSigns = false;\n\n            } else if (chars[i] == '.') {\n                if (hasDecPoint || hasExp) {\n                    // two decimal points or dec in exponent   \n                    return false;\n                }\n                hasDecPoint = true;\n            } else if (chars[i] == 'e' || chars[i] == 'E') {\n                // we've already taken care of hex.\n                if (hasExp) {\n                    // two E's\n                    return false;\n                }\n                if (!foundDigit) {\n                    return false;\n                }\n                hasExp = true;\n                allowSigns = true;\n            } else if (chars[i] == '+' || chars[i] == '-') {\n                if (!allowSigns) {\n                    return false;\n                }\n                allowSigns = false;\n                foundDigit = false; // we need a digit after the E\n            } else {\n                return false;\n            }\n            i++;\n        }\n        if (i < chars.length) {\n            if (chars[i] >= '0' && chars[i] <= '9') {\n                // no type qualifier, OK\n                return true;\n            }\n            if (chars[i] == 'e' || chars[i] == 'E') {\n                // can't have an E at the last byte\n                return false;\n            }\n            if (!allowSigns\n                    && (chars[i] == 'd'\n                    || chars[i] == 'D'\n                    || chars[i] == 'f'\n                    || chars[i] == 'F')) {\n                return foundDigit;\n            }\n            if (chars[i] == 'l'\n                    || chars[i] == 'L') {\n                // not allowing L with an exponent\n                return foundDigit && !hasExp;\n            }\n            // last character is illegal\n            return false;\n        }\n        // allowSigns is true iff the val ends in 'E'\n        // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass\n        return !allowSigns && foundDigit;\n    }\n\n}\n"
  }
]