[
  {
    "path": ".gitignore",
    "content": ".idea\nbin\n.project\n.classpath\n.settings\ntarget/\n"
  },
  {
    "path": "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": "README.md",
    "content": "turnserver\n==========\n\nWelcome to the TurnServer project - open-source TURN server implementation.\n\nThe TURN protocol allows a client to obtain IP addresses and ports from a relay server. It is most useful for endpoints located behind restrictive NATs or firewalls that wish to receive media from another peer.\n\nThe TurnServer project aims to be fully compliant with the TURN and STUN Request For Comments (respectively RFC 5766 and RFC 5389). It also supports RFC6156 namely TURN-IPV6 (relay between IPv4-IPv6, IPv6-IPv4 and IPv6-IPv6 addresses) and RFC6062 namely TURN-TCP (relay data with TCP).\n\nTurnServer is freely available under the terms of the Apache Public License 2.0.\n"
  },
  {
    "path": "build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<project name=\"turnserver\" basedir=\".\" default=\"rebuild\">\n\t<property name=\"dest\" value=\"classes\"/>\n    <property name=\"dest-test\" value=\"classes-test\"/>\n\t<property name=\"lib\" value=\"lib\"/>\n\t<property name=\"src\" value=\"src\"/>\n\t<property name=\"test\" value=\"test\"/>\n    <property name=\"cmd.args\" value=\"0.0.0.0 3487\"/>\n\t<property name=\"turnserver.jar\" value=\"turnserver.jar\"/>\n\t<property name=\"doc\" value=\"doc\"/>\n\t<property name=\"java.doc\" value=\"${doc}/api\"/>\n\n\t<path id=\"project.class.path\">\n\t\t<pathelement location=\"${dest}\"/>\n\t\t<pathelement location=\"${lib}/jain-sdp.jar\"/>\n\t\t<pathelement location=\"${lib}/weupnp-0.1.2-SNAPSHOT.jar\"/>\n\t\t<pathelement location=\"${lib}/ice4j.jar\"/>\n<!--\t\t<pathelement location=\"G:\\\\myPoject\\ice4jProj\\ice4j-read-only\\\\ice4j.jar\"/>  -->\n\t</path>\n    <path id=\"test.class.path\">\n        <path refid=\"project.class.path\" />\n        <pathelement location=\"${dest-test}\"/>\n    </path>\n\n\t<!--Patternset to exclude files from the output directory:-->\n\t<patternset id=\"dest.exclude\">\n\t\t<exclude name=\"package cache/\"/>\n\t\t<exclude name=\"dependency cache/\"/>\n\t</patternset>\n\n\t<!--  ANT TARGETS -->\n\n\t<!-- compiles all classes -->\n\t<target name=\"compile\" depends=\"init\">\n\t\t<javac classpathref=\"project.class.path\"\n               debug=\"true\"\n               deprecation=\"true\"\n               destdir=\"${dest}\"\n               nowarn=\"false\"\n               optimize=\"true\"\n               target=\"1.5\"\n               source=\"1.5\"\n               includeantruntime=\"false\">\n\t\t\t<src path=\"${src}\"/>\n\t\t\t<compilerarg value=\"-Xlint\"/>\n\t\t</javac>\n\t</target>\n\t\n\t<!-- compiles all tests -->\n\t    <target name=\"compile-tests\" depends=\"init\">\n\t        <javac classpathref=\"test.class.path\"\n\t               debug=\"true\"\n\t               deprecation=\"true\"\n\t               destdir=\"${dest-test}\"\n\t               nowarn=\"false\"\n\t               optimize=\"true\"\n\t               target=\"1.5\"\n\t               source=\"1.5\">\n\t            <src path=\"${test}\"/>\n\t            <compilerarg value=\"-Xlint\"/>\n\t        </javac>\n\t    </target>\n\n\t<!-- copies ressource files if any to the classes directory -->\n\t<target name=\"resource\">\n\t\t<copy todir=\"${dest}\">\n\t\t\t<fileset dir=\"${src}\">\n\t\t\t\t<include name=\"**/*.jpe\"/>\n\t\t\t\t<include name=\"**/*.jpeg\"/>\n\t\t\t\t<include name=\"**/*.rmf\"/>\n\t\t\t\t<include name=\"**/*.wav\"/>\n\t\t\t\t<include name=\"**/*.mid\"/>\n\t\t\t\t<include name=\"**/*.midi\"/>\n\t\t\t\t<include name=\"**/*.au\"/>\n\t\t\t\t<include name=\"**/*.gif\"/>\n\t\t\t\t<include name=\"**/*.png\"/>\n\t\t\t\t<include name=\"**/*.jpg\"/>\n\t\t\t\t<include name=\"**/*.aiff\"/>\n\t\t\t\t<include name=\"**/*.properties\"/>\n\t\t\t</fileset>\n\t\t</copy>\n\t</target>\n\n\t<!-- creates the javadocs -->\n\t<target name=\"javadoc\">\n\t\t<javadoc author=\"true\" destdir=\"${java.doc}\" package=\"true\">\n\t\t\t<fileset dir=\"${src}\"/>\n\t\t</javadoc>\n\t</target>\n\n\t<!-- delete the contents of the classes directory-->\n\t<target name=\"clean\">\n\t\t<delete failonerror=\"false\" includeemptydirs=\"true\">\n\t\t\t<fileset dir=\"${dest}\"/>\n            <fileset dir=\"${dest-test}\"/>\n\t\t\t<fileset dir=\"doc\" />\n\t\t</delete>\n\t\t<delete file=\"${turnserver.jar}\" failonerror=\"true\" quiet=\"false\"/>\n\t</target>\n\n\t<!-- make everything -->\n\t<target name=\"make\" depends=\"compile,resource,jar\"/>\n\n\t<!-- clean and make everything -->\n\t<target name=\"rebuild\" depends=\"clean,make\" />\n\n\t<!-- make javadoc -->\n\t<target name=\"doc\" depends=\"make,javadoc\" />\n\n\t<!-- create needed subdirs-->\n\t<target name=\"init\">\n\t\t<mkdir dir=\"${dest}\"/>\n        <mkdir dir=\"${dest-test}\"/>\n\t</target>\n\n\t<!-- create jar file-->\n\t<target name=\"jar\" depends=\"compile\">\n\t\t<jar compress=\"true\" destfile=\"${turnserver.jar}\">\n\t\t\t<fileset dir=\"${dest}\">\n\t\t\t\t<patternset refid=\"dest.exclude\"/>\n\t\t\t\t<include name=\"**/*.*\"/>\n\t\t\t</fileset>\n\t\t</jar>\n\t</target>\n\n\t<!-- runs our Turn Server -->\n\t<target name=\"turn-server\" depends=\"rebuild\">\n\t\t<java fork=\"true\"\n\t\t\tclassname=\"org.jitsi.turnserver.stack.TurnServer\"\n\t\t    classpathref=\"project.class.path\">\n            <arg line=\"cmd.args\" />\n\t\t\t<!-- Tell java.util.logging about our logging preferences -->\n\t\t\t<sysproperty key=\"java.util.logging.config.file\"\n\t\t                         value=\"lib/logging.properties\"/>\n    \t</java>\n\t</target>\n\n\t<!-- runs our Turn Client -->\n\t<target name=\"turn-udp-client\">\n\t\t<java fork=\"true\"\n\t\t\tclassname=\"org.jitsi.turnserver.turnClient.TurnAllocationClient\"\n\t\t\tclasspathref=\"project.class.path\">\n\n\t\t\t<!-- Tell java.util.logging about our logging preferences -->\n\t\t\t<sysproperty key=\"java.util.logging.config.file\"\n\t\t\t\t\t\t value=\"lib/logging.properties\"/>\n\t\t</java>\n\t</target>\n\t\n\t<!-- runs our Turn Tcp Client -->\n\t<target name=\"turn-tcp-client\">\n\t\t<java fork=\"true\"\n\t\t\tclassname=\"org.jitsi.turnserver.turnClient.TurnTcpAllocationClient\"\n\t\t\tclasspathref=\"project.class.path\">\n\n\t\t\t<!-- Tell java.util.logging about our logging preferences -->\n\t\t\t<sysproperty key=\"java.util.logging.config.file\"\n\t\t\t\t\t\t value=\"lib/logging.properties\"/>\n\t\t</java>\n\t</target>\n\t\n\t<!-- runs our Turn Tcp Peer -->\n\t<target name=\"turn-tcp-peer\">\n\t\t<java fork=\"true\"\n\t\t\tclassname=\"org.jitsi.turnserver.turnClient.TcpPeer\"\n\t\t\tclasspathref=\"project.class.path\">\n\n\t\t\t<!-- Tell java.util.logging about our logging preferences -->\n\t\t\t<sysproperty key=\"java.util.logging.config.file\"\n\t\t\t\t\t\t value=\"lib/logging.properties\"/>\n\t\t</java>\n\t</target>\n\t\n\t<!-- runs our ICE test class -->\n\t\t<target name=\"test-ice\">\n\t\t\t<java fork=\"true\"\n\t\t\t\tclassname=\"test.Ice\"\n\t\t\t    classpathref=\"test.class.path\">\n\t            <!-- Tell java.util.logging about our logging preferences -->\n\t\t\t\t<sysproperty key=\"java.util.logging.config.file\"\n\t\t\t                         value=\"lib/logging.properties\"/>\n\t    \t</java>\n\t\t</target>\n\n</project>\n"
  },
  {
    "path": "pom.xml",
    "content": "<project\n    xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.jitsi</groupId>\n    <artifactId>jitsi-universe</artifactId>\n    <version>1.0-SNAPSHOT</version>\n    <relativePath>../jitsi-universe/pom.xml</relativePath>\n  </parent>\n\n  <artifactId>turnserver</artifactId>\n  <version>1.0-SNAPSHOT</version>\n  <packaging>jar</packaging>\n\n  <name>turnserver</name>\n  <url>https://github.com/jitsi/turnserver</url>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.jitsi</groupId>\n      <artifactId>ice4j</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>javax.sdp</groupId>\n      <artifactId>jain-sdp</artifactId>\n    </dependency>\n    <dependency>\n      <groupId>org.bitlet</groupId>\n      <artifactId>weupnp</artifactId>\n    </dependency>\n    <!-- test -->\n    <dependency>\n      <groupId>junit</groupId>\n      <artifactId>junit</artifactId>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <plugins>\n      <plugin>\n        <groupId>org.apache.maven.plugins</groupId>\n        <artifactId>maven-surefire-plugin</artifactId>\n        <configuration>\n          <includes>\n            <include>**/*TestSuite.*</include>\n          </includes>\n        </configuration>\n      </plugin>\n    </plugins>\n  </build>\n\n  <repositories>\n    <repository>\n      <id>jitsi-maven-repository-releases</id>\n      <layout>default</layout>\n      <name>Jitsi Maven Repository (Releases)</name>\n      <releases>\n        <enabled>true</enabled>\n      </releases>\n      <snapshots>\n        <enabled>false</enabled>\n      </snapshots>\n      <url>https://github.com/jitsi/jitsi-maven-repository/raw/master/releases/</url>\n    </repository>\n    <repository>\n      <id>jitsi-maven-repository-snapshots</id>\n      <layout>default</layout>\n      <name>Jitsi Maven Repository (Snapshots)</name>\n      <releases>\n        <enabled>false</enabled>\n      </releases>\n      <snapshots>\n        <enabled>true</enabled>\n      </snapshots>\n      <url>https://github.com/jitsi/jitsi-maven-repository/raw/master/snapshots/</url>\n    </repository>\n  </repositories>\n</project>\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/IndicationListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Abstract class for Indication Listener.\n * \n * @author Aakash Garg\n */\npublic abstract class IndicationListener implements MessageEventHandler \n{\n    /**\n     * The turnStack for this instance.\n     */\n    private final TurnStack turnStack;\n    \n    /**\n     * Represents if the listener is started or not.\n     */\n    private boolean started = false;\n    \n    /**\n     * Represents the localAddress associated with the listener.\n     */\n    private TransportAddress localAddress;\n\n    /**\n     * The turnStack to call.\n     * @param turnStack\n     */\n    public IndicationListener(TurnStack turnStack)\n    {\n\tthis.turnStack = turnStack;\n    }\n    \n    /**\n     * Checks if the message is an Indication message. If yes it then finds the\n     * five tuple and corresponding allocation and calls the handleIndication.\n     */\n    @Override\n    public void handleMessageEvent(StunMessageEvent evt) {\n\tMessage message = evt.getMessage();\n\tif(Message.isIndicationType(message.getMessageType()))\n\t{\n\t    Indication ind = (Indication) message;\n\t    \n\t    TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = serverAddress.getTransport();\n            FiveTuple fiveTuple =\n                new FiveTuple(clientAddress, serverAddress, transport);\n            Allocation alloc = turnStack.getServerAllocation(fiveTuple);\n            \n\t    this.handleIndication(ind,alloc);\n\t}\t\t\n    }\n    \n    /**\n     * Sets the turnStack for this class.\n     * @return\n     */\n    public TurnStack getTurnStack()\n    {\n\treturn this.turnStack;\n    }\n    \n    /**\n     * Sets the localAddress.\n     * \n     * @param localAddress\n     *            the localAddress to listen on.\n     */\n    public void setLocalAddress(TransportAddress localAddress)\n    {\n\tthis.localAddress = localAddress;\n    }\n    \n    /**\n     * Handles the Indication message.\n     * It must be implemented by the subclass.\n     * \n     * @param ind\n     *            the Indication to handle.\n     * @param alloc\n     *            the corresponding to the request.\n     */\n    abstract public void handleIndication(Indication ind, Allocation alloc);\n\n    /**\n     * Starts this <tt>IndicationListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addIndicationListener(localAddress, this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>IndicationListenerr</tt>. A stopped\n     * <tt>IndicationListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeIndicationListener(localAddress, this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/TurnException.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver;\n\nimport org.ice4j.StunException;\n\n/**\n * @author Aakash Garg\n * \n */\npublic class TurnException\n    extends StunException\n{\n\n    /**\n     * \n     */\n    private static final long serialVersionUID = -8004612606830162094L;\n\n    /**\n     * \n     */\n    public TurnException()\n    {\n    }\n\n    /**\n     * @param id\n     */\n    public TurnException(int id)\n    {\n        super(id);\n    }\n\n    /**\n     * @param message\n     */\n    public TurnException(String message)\n    {\n        super(message);\n    }\n\n    /**\n     * @param id\n     * @param message\n     */\n    public TurnException(int id, String message)\n    {\n        super(id, message);\n    }\n\n    /**\n     * @param id\n     * @param message\n     * @param cause\n     */\n    public TurnException(int id, String message, Throwable cause)\n    {\n        super(id, message, cause);\n    }\n\n    /**\n     * @param message\n     * @param cause\n     */\n    public TurnException(String message, Throwable cause)\n    {\n        super(message, cause);\n    }\n\n    /**\n     * @param cause\n     */\n    public TurnException(Throwable cause)\n    {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/TurnStackProperties.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\n\n/**\n * The class contains a number of property names and their default values that\n * we use to configure the behavior of the Turnserver stack.\n *\n * @author Aakash Garg.\n */\npublic class TurnStackProperties extends StackProperties\n{\n    /**\n     * Our class logger.\n     */\n    private static final Logger logger\n        = Logger.getLogger(TurnStackProperties.class.getName());\n\n    public static final String TURNSERVER_UDP_PORT \n    \t= \"org.jitsi.turnserver.udp_port\";\n\n    public static final int DEFAULT_TURNSERVER_UDP_PORT = 3478;\n\n    public static final String TURNSERVER_MIN_PORT \n\t= \"org.jitsi.turnserver.min_port\";\n\n    public static final int DEFAULT_TURNSERVER_MIN_PORT = 49152;\n\n    public static final String TURNSERVER_MAX_PORT \n\t= \"org.jitsi.turnserver.max_port\";\n\n    public static final int DEFAULT_TURNSERVER_MAX_PORT = 65535;\n\n    public static final String ALLOCATION_LIFETIME \n\t= \"org.jitsi.turnserver.allocation_lifetime\";\n\n    public static final int DEFAULT_ALLOCATION_LIFETIME = 10 * 60 * 1000;\n    \n    public static final String MAX_ALLOCATIONS \n\t= \"org.jitsi.turnserver.max_allocations\";\n\n    public static final int DEFAULT_MAX_ALLOCATIONS = 50;\n    \n    public static final String CHANNELBIND_LIFETIME \n\t= \"org.jitsi.turnserver.channelbind_lifetime\";\n\n    public static final int DEFAULT_CHANNELBIND_LIFETIME = 10 * 60 * 1000;\n\n    public static final String MAX_PERMISSIONS_PER_ALLOCATION \n\t= \"org.jitsi.turnserver.max_permissions_per_allocation\";\n\n    public static final int DEFAULT_MAX_PERMISSIONS_PER_ALLOCATION = 10;\n\n    public static final String PERMISSION_LIFETIME \n\t= \"org.jitsi.turnserver.permission_lifetime\";\n\n    public static final int DEFAULT_PERMISSION_LIFETIME = 300 * 1000;\n    \n    public static final String MAX_CHANNELBINDS_PER_ALLOCATION \n\t= \"org.jitsi.turnserver.max_channelbinds_per_allocation\";\n\n    public static final int DEFAULT_MAX_CHANNELBINDS_PER_ALLOCATION = 10;\n\n    public static final String REALM \n\t= \"org.jitsi.turnserver.realm\";\n   \n    public static final String DEFAULT_REALM \n \t= \"org.jitsi.turnserver\";\n    \n    public static final String DEFAULT_ACCOUNTS_FILE\n    \t= \"\";\n    \n    public static final String ACCOUNTS_FILE\n    \t= \"\";\n\n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/AllocationResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.io.IOException;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\nimport org.jitsi.turnserver.stack.TurnStack;\n\n/**\n * The class that would be handling to incoming Allocation responses.\n * \n * @author Aakash Garg\n */\npublic class AllocationResponseCollector\n    implements ResponseCollector\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>AllocationresponseCollector</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(AllocationResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new AllocationresponseCollector\n     * \n     * @param turnStack\n     */\n    public AllocationResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)\n        {\n            ErrorCodeAttribute errorCodeAttribute =\n                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);\n            NonceAttribute nonceAttr = (NonceAttribute) message\n\t\t    .getAttribute(Attribute.NONCE);\n//\t    System.out.println(\"Nonce : \"+new Nonce(nonceAttr.getNonce()));\n            Request request = MessageFactory.createAllocateRequest();\n            TransactionID tran = TransactionID.createNewTransactionID();\n            try {\n\t\trequest.setTransactionID(tran.getBytes());\n\t    } catch (StunException e1) {\n\t\tSystem.err.println(\"Unable to set tran ID.\");\n\t    }\n            request.putAttribute(nonceAttr);\n            String username = \"JitsiGsocStudent\";\n\t    UsernameAttribute usernameAttr = AttributeFactory\n\t\t    .createUsernameAttribute(username+\":\");\n/*\t    \n\t    byte[] key = this.stunStack.getCredentialsManager().getLocalKey(\n\t\t    username);\n\t    System.out.println(\"Username found \"\n\t\t    + (this.stunStack.getCredentialsManager()\n\t\t\t    .checkLocalUserName(username)));\n\t    System.out.println(\"User \"\n\t\t    + username\n\t\t    + \" found : \"\n\t\t    + TurnStack.toHexString(key));\n\t    \n\t    byte[] messageB = request.encode(stunStack);\n*/\t    MessageIntegrityAttribute msgInt = AttributeFactory\n\t\t    .createMessageIntegrityAttribute(username);\n\t    RequestedTransportAttribute reqTrans = AttributeFactory\n\t\t    .createRequestedTransportAttribute(\n\t\t\t    RequestedTransportAttribute.UDP);\n\t    try{\n//\t\t    msgInt.encode(stunStack, messageB, 0, messageB.length);\t\t\n\t    }catch(Exception e)\n\t    {\n\t\te.printStackTrace();\n\t    }\n\t    request.putAttribute(reqTrans);\n\t    request.putAttribute(usernameAttr);\n\t    request.putAttribute(msgInt);\n\t    try {\n\t\tthis.stunStack.sendRequest(request, evt.getRemoteAddress(),\n\t\t    evt.getLocalAddress(), this);\n\t    }\n\t    catch (Exception e) {\n\t\te.printStackTrace();\n//\t\tSystem.err.println(e.getMessage());\n\t    }\n            if(errorCodeAttribute != null)\n            {\n\t\tSystem.out.println(\"Error Code : \"\n\t\t\t+ (int) errorCodeAttribute.getErrorCode());\n            }\n            switch (errorCodeAttribute.getErrorCode())\n            {\n            case ErrorCodeAttribute.BAD_REQUEST:\n                // code for bad response error\n                break;\n            case ErrorCodeAttribute.UNAUTHORIZED:\n                // code for unauthorised error code\n                break;\n            case ErrorCodeAttribute.FORBIDDEN:\n                // code for forbidden error code\n                break;\n            case ErrorCodeAttribute.UNKNOWN_ATTRIBUTE:\n                // code for Unknown Attribute error code\n                break;\n            case ErrorCodeAttribute.ALLOCATION_MISMATCH:\n                // code for Allocation mismatch Error\n                break;\n            case ErrorCodeAttribute.STALE_NONCE:\n                // code for Stale Nonce error code\n                break;\n            case ErrorCodeAttribute.WRONG_CREDENTIALS:\n                // code for wrong credentials error code\n                break;\n            case ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL:\n                // code for unsupported transport protocol\n                break;\n            case ErrorCodeAttribute.ALLOCATION_QUOTA_REACHED:\n                // code for allocation quota reached\n                break;\n            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:\n                // code for insufficient capacity\n                break;\n                \n            }\n        }\n        else if (message.getMessageType() == Message.ALLOCATE_RESPONSE)\n        {\n            System.out.println(\"Allocate Sucess Response.\");\n            // code for doing processing of Allocation success response\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ChannelBindResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming ChannelBind\n * response.\n * \n * @author Aakash Garg\n */\npublic class ChannelBindResponseCollector\n    implements ResponseCollector\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ChannelBindresponseCollector</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ChannelBindResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new ChannelBindresponseCollector\n     * \n     * @param turnStack\n     */\n    public ChannelBindResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CHANNELBIND_ERROR_RESPONSE)\n        {\n            ErrorCodeAttribute errorCodeAttribute =\n                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);\n            switch (errorCodeAttribute.getErrorCode())\n            {\n            case ErrorCodeAttribute.BAD_REQUEST:\n                // code for bad response error\n                break;\n            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:\n                // logic for processing insufficient capacity error code\n                break;\n            }\n        }\n        else if (message.getMessageType() == Message.CHANNELBIND_RESPONSE)\n        {\n            // logic for processing the success response.\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ConnectResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming Connect response.\n * \n * @author Aakash Garg\n */\npublic class ConnectResponseCollector\n    implements ResponseCollector\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ConnectresponseCollector</tt> class\n     * and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ConnectResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new ConnectresponseCollector\n     * \n     * @param turnStack\n     */\n    public ConnectResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CONNECT_ERROR_RESPONSE)\n        {\n            ErrorCodeAttribute errorCodeAttribute =\n                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);\n            switch (errorCodeAttribute.getErrorCode())\n            {\n            case ErrorCodeAttribute.ALLOCATION_MISMATCH:\n                // code for bad response error\n                break;\n            case ErrorCodeAttribute.CONNECTION_ALREADY_EXISTS:\n                // code for processing connection already exists error\n                break;\n            case ErrorCodeAttribute.FORBIDDEN:\n                // code for processing forbidden error code\n                break;\n            case ErrorCodeAttribute.CONNECTION_TIMEOUT_OR_FAILURE:\n                // code for processing connection timeout or failure error code.\n                break;\n            }\n        }\n        else if (message.getMessageType() == Message.CONNECT_RESPONSE)\n        {\n            // code for doing processing of Connect success response\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ConnectionBindResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming ConnectionBind\n * response.\n * \n * @author Aakash Garg\n */\npublic class ConnectionBindResponseCollector\n    implements ResponseCollector\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ConnectionBindresponseCollector</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ConnectionBindResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new ConnectionBindresponseCollector\n     * \n     * @param turnStack\n     */\n    public ConnectionBindResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)\n        {\n            ErrorCodeAttribute errorCodeAttribute =\n                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);\n            switch (errorCodeAttribute.getErrorCode())\n            {\n            case ErrorCodeAttribute.BAD_REQUEST:\n                // code for bad response error\n                break;\n            }\n        }\n        else if (message.getMessageType() == Message.ALLOCATE_RESPONSE)\n        {\n            // code for doing processing of ConnectionBind success response\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/CreatePermissionResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming CreatePermission\n * response.\n * \n * @author Aakash Garg\n */\npublic class CreatePermissionResponseCollector\n    implements ResponseCollector\n{\n    /**\n     * The <tt>Logger</tt> used by the\n     * <tt>CreatePermissionResponseCollector</tt> class and its instances for\n     * logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(CreatePermissionResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new CreatePermissionResponseCollector\n     * \n     * @param turnStack\n     */\n    public CreatePermissionResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)\n        {\n            ErrorCodeAttribute errorCodeAttribute =\n                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);\n            switch (errorCodeAttribute.getErrorCode())\n            {\n            case ErrorCodeAttribute.BAD_REQUEST:\n                // logic for processing bad request error\n                break;\n            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:\n                // logic for processing insufficient capacity error\n                break;\n            case ErrorCodeAttribute.FORBIDDEN:\n                // logic for processing forbidden error code\n                break;\n            default:\n                logger.finer(\"error : Received error response with error code \"\n                    + errorCodeAttribute.getErrorCode() + evt);\n            }\n        }\n        else\n        {\n            return;\n        }\n\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n        // TODO Auto-generated method stub\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/RefreshResponseCollector.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.collectors;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming Refresh\n * responses.\n * \n * @author Aakash Garg\n */\npublic class RefreshResponseCollector\n    implements ResponseCollector\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>RefreshresponseCollector</tt> class\n     * and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(RefreshResponseCollector.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * Creates a new RefreshResponseCollector\n     * \n     * @param turnStack\n     */\n    public RefreshResponseCollector(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)\n     */\n    @Override\n    public void processResponse(StunResponseEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.finer(\"Received response \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.REFRESH_ERROR_RESPONSE)\n        {\n            // delete allocation\n        }\n        else if (message.getMessageType() == Message.REFRESH_RESPONSE)\n        {\n            // update allocation\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)\n     */\n    @Override\n    public void processTimeout(StunTimeoutEvent event)\n    {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/AllocationRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * The class that would be handling and responding to incoming Allocation\n * requests that are Allocation and sends a success or error response.\n * \n * @author Aakash Garg\n */\npublic class AllocationRequestListener\n    implements RequestListener\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>AllocationRequestListener</tt> class\n     * and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(AllocationRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>AllocationrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new AllocationRequestListener\n     * \n     * @param turnStack\n     */\n    public AllocationRequestListener(StunStack stunStack)\n    {\n        if (stunStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) stunStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.ALLOCATE_REQUEST)\n        {\n\t    logger.finest(\"Received a Allocation Request from \"\n\t\t    + evt.getRemoteAddress());\n           \n            Response response = null;\n            RequestedTransportAttribute requestedTransportAttribute =\n                (RequestedTransportAttribute) message\n                    .getAttribute(Attribute.REQUESTED_TRANSPORT);\n\n            DontFragmentAttribute dontFragmentAttribute =\n                (DontFragmentAttribute) message\n                    .getAttribute(Attribute.DONT_FRAGMENT);\n\n            ReservationTokenAttribute reservationTokenAttribute =\n                (ReservationTokenAttribute) message\n                    .getAttribute(Attribute.RESERVATION_TOKEN);\n\n            LifetimeAttribute lifetimeAttribute = \n                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);\n            \n            EvenPortAttribute evenPort = \n                (EvenPortAttribute) message.getAttribute(Attribute.EVEN_PORT);\n            \n            if (lifetimeAttribute == null)\n            {\n                lifetimeAttribute =\n                    AttributeFactory\n                        .createLifetimeAttribute(\n                            (int) (Allocation.DEFAULT_LIFETIME / 1000));\n            }\n            \n            EvenPortAttribute evenPortAttribute =\n                (EvenPortAttribute) message.getAttribute(Attribute.EVEN_PORT);\n            \n            TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = serverAddress.getTransport();\n            FiveTuple fiveTuple =\n                new FiveTuple(clientAddress, serverAddress, transport);\n              \n            Character errorCode = null;\n            if(!this.turnStack.canHaveMoreAllocations())\n            {\n                errorCode = ErrorCodeAttribute.ALLOCATION_QUOTA_REACHED;\n            }\n            else if (requestedTransportAttribute == null)\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else if (requestedTransportAttribute.getRequestedTransport() \n                == RequestedTransportAttribute.TCP)\n            {\n                if (!this.turnStack.isTCPAllowed())\n                    errorCode =\n                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;\n                else if (reservationTokenAttribute != null)\n                {\n                    logger.finest(\"error : reservation token found in TCP message.\");\n                    errorCode =\n                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;\n                }\n                else if (evenPort != null)\n                {\n                    logger.finest(\"error : even port found in TCP message.\");\n                    errorCode =\n                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;\n                }\n                else if (dontFragmentAttribute != null)\n                {\n                    logger.finest(\"error : dont fragment found in TCP message.\");\n                    errorCode =\n                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;\n                }\n            }\n            else if (requestedTransportAttribute.getRequestedTransport() \n                == RequestedTransportAttribute.UDP \n                && !this.turnStack.isUDPAllowed())\n            {\n                errorCode = ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;\n                logger.finest(\"UDP not alllowed on Allocation Requests.\");\n            }\n            else if (reservationTokenAttribute != null\n                && evenPortAttribute != null)\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n                logger\n                    .finest(\"Both reservation Token and Even PortAttribute are found in Allocation request.\");\n            }\n            \n            if (turnStack.getServerAllocation(fiveTuple)!=null)\n            {\n                errorCode = ErrorCodeAttribute.ALLOCATION_MISMATCH; \n                logger.finest(\"Allocation not found for the \"+fiveTuple);\n            }\n            // do other checks here\n            \n            if (errorCode == null)\n            {\n                if(evenPortAttribute==null)\n                {\n                    evenPortAttribute =\n                        AttributeFactory.createEvenPortAttribute(false);\n                }\n                TransportAddress relayAddress = turnStack.getNewRelayAddress(\n                    evenPortAttribute.isRFlag(), serverAddress.getTransport());\n/*                logger.finest(\"Added a new Relay Address \"+relayAddress);\n                System.out.println(\"Added a new Relay Address \"+relayAddress\n                \t+\" for client \"+evt.getRemoteAddress());\n*/              \n                Allocation allocation = null;\n                synchronized(this)\n                {\n                    allocation =\n                        new Allocation(relayAddress, fiveTuple,\n                            lifetimeAttribute.getLifetime());\n                    this.turnStack.addNewServerAllocation(allocation);\n//                    System.out.println(\"Added a new allocation.\");\n                }\n                logger.finest(\"Added a new Allocation with relay address :\"\n\t\t\t\t+ allocation.getRelayAddress()+\" for client \"\n\t\t\t\t+evt.getRemoteAddress());\n                \n                response = MessageFactory.createAllocationResponse(\n                     (Request) message,\n                     allocation.getFiveTuple().getClientTransportAddress(), \n                     allocation.getRelayAddress(), \n                     (int) allocation.getLifetime());\n                \n                XorRelayedAddressAttribute relayedXorAddress \n                    = AttributeFactory.createXorRelayedAddressAttribute(\n                            allocation.getRelayAddress(),\n                            evt.getTransactionID().getBytes());\n                response.putAttribute(relayedXorAddress);\n                \n                LifetimeAttribute lifetime \n                    = AttributeFactory.createLifetimeAttribute(\n                        (int)(allocation.getLifetime()));\n                response.putAttribute(lifetime);\n                \n                XorMappedAddressAttribute clientXorAddress \n                    = AttributeFactory.createXorMappedAddressAttribute(\n                        clientAddress,\n                        evt.getTransactionID().getBytes());\n               response.putAttribute(clientXorAddress);\n                \n                if(evenPort!=null)\n                {\n                    // TODO : logic for process and creating Reservation Token.\n                    byte[] token = {7,7,7,7};\n                    ReservationTokenAttribute reservationToken\n                        = AttributeFactory.createReservationTokenAttribute(\n                            token);\n                    response.putAttribute(reservationToken);\n                    if(evenPort.isRFlag())\n                    {\n                        TransportAddress relayAddess\n                            = allocation.getRelayAddress();\n                        TransportAddress nextAddress \n                            = new TransportAddress(\n                                relayAddress.getAddress(),\n                                relayAddress.getPort()+1,\n                                relayAddress.getTransport());\n                        boolean isReserved\n                            = this.turnStack.reservePort(nextAddress);\n                        if(isReserved)\n                        {\n                            logger.log(\n                                Level.FINEST,\n                                nextAddress+\" reserved by \"+fiveTuple);\n                        }\n                        else\n                        {\n                            logger.log(\n                                Level.FINEST,\n                                nextAddress+\" not reserved by \"+fiveTuple);\n                        }\n                    }\n                }               \n            }\n            else\n            {\n                System.err.println(\"Error Code \" + (int)errorCode\n                        + \" on Allocation Request\");\n                logger.finest(\"Error Code \" + (int)errorCode\n                    + \" on Allocation Request\");\n                response =\n                    MessageFactory.createAllocationErrorResponse(errorCode);\n            }\n            \n            try\n            {\n                logger\n                    .fine(\"Trying to send response to \"\n                        + evt.getRemoteAddress() + \" from \"\n                        + evt.getLocalAddress());\n                turnStack.sendResponse(\n                    evt.getTransactionID().getBytes(), response,\n                    evt.getLocalAddress(), evt.getRemoteAddress());\n                logger.finest(\"Response sent.\");\n            }\n            catch (Exception e)\n            {\n        \tSystem.err.println(\"Failed to send response\");\n                logger.log(\n                    Level.INFO, \"Failed to send \" + response + \" through \"\n                        + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /**\n     * Starts this <tt>AllocationRequestListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>AllocationRequestListenerr</tt>. A stopped\n     * <tt>AllocationRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/BindingRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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 org.jitsi.turnserver.listeners;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * The class that would be handling and responding to incoming requests that are\n * validated and sends a SUCCESS response\n * \n * @author Aakash Garg\n */\npublic class BindingRequestListener\n    implements RequestListener\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>BindingRequestListener</tt> class and\n     * its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(BindingRequestListener.class.getName());\n\n    private final StunStack stunStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>ValidatedrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new BindingRequestListener\n     * \n     * @param turnStack\n     */\n    public BindingRequestListener(StunStack stunStack)\n    {\n        this.stunStack = stunStack;\n    }\n\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n        }\n        Message message = evt.getMessage();\n\n        if (message.getMessageType() == Message.BINDING_REQUEST)\n        {\n            logger.finest(\"Received a Binding Request from \"\n                + evt.getRemoteAddress());\n            TransportAddress mappedAddress = evt.getRemoteAddress();\n            // Response response =\n            // MessageFactory.createBindingResponse(request,mappedAddress);\n            TransportAddress sourceAddress = evt.getLocalAddress();\n            TransportAddress changedAddress =\n                new TransportAddress(\"stunserver.org\", 3489, Transport.UDP);\n            Response response = MessageFactory.create3489BindingResponse(\n                mappedAddress, sourceAddress, changedAddress);\n\n            try\n            {\n                stunStack.sendResponse(\n                    evt.getTransactionID().getBytes(), response,\n                    evt.getLocalAddress(), evt.getRemoteAddress());\n                logger.finest(\"Binding Response Sent.\");\n            }\n            catch (Exception e)\n            {\n                logger.log(\n                    Level.INFO, \"Failed to send \" + response + \" through \"\n                        + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n    }\n\n    /**\n     * Starts this <tt>BindingRequestListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            stunStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>ValidatedRequestListenerr</tt>. A stopped\n     * <tt>ValidatedRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        stunStack.removeRequestListener(this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ChannelBindRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * The class that would be handling and responding to incoming ChannelBind\n * requests that are validated and sends a success or error response\n * \n * @author Aakash Garg\n */\npublic class ChannelBindRequestListener\n    implements RequestListener\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ChannelBindRequestListener</tt> class\n     * and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ChannelBindRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>ChannelBindrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new ChannelBindRequestListener\n     * \n     * @param turnStack\n     */\n    public ChannelBindRequestListener(StunStack turnStack)\n    {\n        if (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n//            logger.finer(\"Received request \" + evt);\n        }\n        \n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CHANNELBIND_REQUEST)\n        {\n            logger.finest(\"Received Channel Bind request \");\n            logger.finest(\"Event tran : \"+evt.getTransactionID());\n            \n            Response response = null;\n \n            TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = serverAddress.getTransport();\n            FiveTuple fiveTuple =\n                new FiveTuple(clientAddress, serverAddress, transport);\n            \n            Allocation allocation \n                = this.turnStack.getServerAllocation(fiveTuple);\n            \n            ChannelNumberAttribute channelNo =\n                (ChannelNumberAttribute) message.getAttribute(\n                    Attribute.CHANNEL_NUMBER);\n            XorPeerAddressAttribute xorPeerAddress =\n                (XorPeerAddressAttribute) message\n                    .getAttribute(Attribute.XOR_PEER_ADDRESS);\n            if(xorPeerAddress!=null)\n            {\n                xorPeerAddress.setAddress(xorPeerAddress.getAddress(),\n                    evt.getTransactionID().getBytes());\n            }\n            \n            logger.finest(\"Adding ChannelBind : \"\n                                    +(int)(channelNo.getChannelNumber())\n                                    +\", \"+xorPeerAddress.getAddress());\n            ChannelBind channelBind = new ChannelBind(\n                                            xorPeerAddress.getAddress(),\n                                            channelNo.getChannelNumber());\n\n            Character errorCode = null;\n            if(channelNo==null || xorPeerAddress==null)\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else if(!ChannelNumberAttribute.isValidRange(\n                channelNo.getChannelNumber()))\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else if (allocation == null\n                || allocation.isBadChannelRequest(channelBind))\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else if(!TurnStack.isIPAllowed(xorPeerAddress.getAddress()))\n            {\n                errorCode = ErrorCodeAttribute.FORBIDDEN;\n            }\n            else if(!allocation.canHaveMoreChannels())\n            {\n                errorCode = ErrorCodeAttribute.INSUFFICIENT_CAPACITY;\n            }\n            \n            if(errorCode != null)\n            {\n                logger.finest(\"Creating ChannelBindError response : \"\n                                        +(int)errorCode);\n                response  \n                    = MessageFactory.createChannelBindErrorResponse(errorCode);\n            }\n            else\n            {\n                logger.finest(\"Creating ChannelBind sucess response\");\n                try\n                {\n                    logger.finer(\"Adding ChannelBind : \"+channelBind);\n                    allocation.addChannelBind(channelBind);\n                }\n                catch(IllegalArgumentException ex)\n                {\n                    logger.log(Level.FINEST,ex.getMessage());\n                }\n                response = MessageFactory.createChannelBindResponse();\n            }\n            \n            try\n            {\n                turnStack.sendResponse(evt.getTransactionID().getBytes(),\n                    response, evt.getLocalAddress(), evt.getRemoteAddress());\n            }\n            catch (Exception e)\n            {\n                logger.log(Level.INFO, \"Failed to send \" + response\n                    + \" through \" + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /**\n     * Starts this <tt>ChannelBindRequestListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>ChannelBindRequestListenerr</tt>. A stopped\n     * <tt>ChannelBindRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.StunMessageEvent;\nimport org.ice4j.Transport;\nimport org.ice4j.TransportAddress;\nimport org.ice4j.attribute.Attribute;\nimport org.ice4j.attribute.AttributeFactory;\nimport org.ice4j.attribute.ConnectionIdAttribute;\nimport org.ice4j.attribute.ErrorCodeAttribute;\nimport org.ice4j.attribute.XorPeerAddressAttribute;\nimport org.ice4j.message.Message;\nimport org.ice4j.message.MessageFactory;\nimport org.ice4j.message.Response;\nimport org.ice4j.socket.IceTcpSocketWrapper;\nimport org.ice4j.stack.RequestListener;\nimport org.ice4j.stack.StunStack;\nimport org.jitsi.turnserver.stack.Allocation;\nimport org.jitsi.turnserver.stack.FiveTuple;\nimport org.jitsi.turnserver.stack.TurnStack;\n\n/**\n * The class that would be handling and responding to incoming Connect requests\n * that are validated and sends a success or error response\n * \n * @author Aakash Garg\n */\npublic class ConnectRequestListener\n    implements RequestListener\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ConnectRequestListener</tt> class and\n     * its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ConnectRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>ValidatedrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new ConnectRequestListener\n     * \n     * @param turnStack\n     */\n    public ConnectRequestListener(StunStack stunStack)\n    {\n        this.turnStack = (TurnStack) stunStack;\n    }\n\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CONNECT_REQUEST)\n        {\n            logger.finer(\"Received Connect request \" + evt);\n\n            Character errorCode = null;\n            XorPeerAddressAttribute peerAddress = null;\n            FiveTuple fiveTuple = null;\n            Response response = null;\n            ConnectionIdAttribute connectionId = null;\n            if (!message.containsAttribute(Attribute.XOR_PEER_ADDRESS))\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else\n            {\n                peerAddress =\n                    (XorPeerAddressAttribute) message\n                        .getAttribute(Attribute.XOR_PEER_ADDRESS);\n                peerAddress.setAddress(\n                    peerAddress.getAddress(), \n                    evt.getTransactionID().getBytes());\n                logger.finest(\"Peer Address requested : \"\n                    + peerAddress.getAddress());\n                TransportAddress clientAddress = evt.getRemoteAddress();\n                TransportAddress serverAddress = evt.getLocalAddress();\n                Transport transport = evt.getLocalAddress().getTransport();\n                fiveTuple =\n                    new FiveTuple(clientAddress, serverAddress, transport);\n                Allocation allocation =\n                    this.turnStack.getServerAllocation(fiveTuple);\n                if (allocation == null)\n                {\n                    errorCode = ErrorCodeAttribute.ALLOCATION_MISMATCH;\n                }\n                else if(!allocation.isPermitted(peerAddress.getAddress())){\n                    errorCode = ErrorCodeAttribute.FORBIDDEN;\n                }\n                else\n                {\n                    // code for processing the connect request.\n                    connectionId = \n                        AttributeFactory.createConnectionIdAttribute();\n                    logger.finest(\"Created ConnectionID : \"\n                        + connectionId.getConnectionIdValue());\n                    try\n                    {\n                        Socket socket =\n                            new Socket(peerAddress.getAddress().getAddress(),\n                                peerAddress.getAddress().getPort());\n                        socket.setSoTimeout(30*1000);\n                        IceTcpSocketWrapper iceSocket =\n                            new IceTcpSocketWrapper(socket);\n                        this.turnStack.addSocket(iceSocket);\n                    }\n                    catch (IOException e)\n                    {\n                        // TODO Auto-generated catch block\n                        e.printStackTrace();\n                    }\n                    /**\n                     * TODO\n                     * Create a new TCP connection to the peer from relay\n                     * address. \n                     * wait for at-least 30 seconds. \n                     * If it fails then send 447 error code. \n                     **/\n                    this.turnStack.addUnAcknowlededConnectionId(\n                        connectionId.getConnectionIdValue(),\n                        peerAddress.getAddress(), allocation);\n                    logger.finest(\"Creating Connect Success Response.\");\n                    response =\n                        MessageFactory.createConnectResponse(connectionId\n                            .getConnectionIdValue());\n                    \n                }\n            }\n            if(errorCode != null){\n                response = MessageFactory.createConnectErrorResponse(errorCode);\n                logger.finest(\"error Code : \"+(int)errorCode+ \" on ConnectRequest\");\n            }\n            try\n            {\n                logger.finest(\"Sending Connect Response\");\n                turnStack.sendResponse(\n                    evt.getTransactionID().getBytes(), response,\n                    evt.getLocalAddress(), evt.getRemoteAddress());\n            }\n            catch (Exception e)\n            {\n            System.err.println(\"Failed to send response\");\n                logger.log(\n                    Level.INFO, \"Failed to send \" + response + \" through \"\n                        + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n        else\n        {\n            return;\n        }\n\n    }\n\n    /**\n     * Starts this <tt>ConnectRequestListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>ConnectRequestListenerr</tt>. A stopped\n     * <tt>ConnectRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectionAttemptIndicationListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.io.*;\nimport java.net.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.socket.*;\nimport org.ice4j.stack.*;\nimport org.ice4j.stunclient.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to handle events when a Connection Attempt Indication is received on\n * CLient Side.\n * \n * @author Aakash Garg\n * \n */\npublic class ConnectionAttemptIndicationListener\n    extends IndicationListener\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>DataIndicationListener</tt> class and\n     * its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ConnectionAttemptIndicationListener.class.getName());\n\n    /**\n     * The request sender to use to send request to Turn server.\n     */\n    private BlockingRequestSender requestSender;\n\n    /**\n     * Constructor to create a ConnectionAttemptIndicationListener with\n     * specified turnStack to use the requestSender will be null and a new\n     * {@link BlockingRequestSender} will be created with new TCP socket to send\n     * request to server.\n     * \n     * @param turnStack the turnStack to use for processing.\n     */\n    public ConnectionAttemptIndicationListener(TurnStack turnStack)\n    {\n        super(turnStack);\n    }\n\n    /**\n     * Constructor to create a ConnectionAttemptIndicationListener with\n     * specified turnStack to use.\n     * \n     * @param turnStack the turnStack to use for processing.\n     * @param requestSender the requestSender to use to send request to server.\n     */\n    public ConnectionAttemptIndicationListener(TurnStack turnStack,\n        BlockingRequestSender requestSender)\n    {\n        super(turnStack);\n        this.requestSender = requestSender;\n    }\n\n    /**\n     * The method to handle the incoming ConnectionAttempt Indications from Turn\n     * Server.\n     */\n    @Override\n    public void handleIndication(Indication ind, Allocation alloc)\n    {\n        if (ind.getMessageType() == Message.CONNECTION_ATTEMPT_INDICATION)\n        {\n            logger.finest(\"Received a connection attempt indication.\");\n            byte[] tranId = ind.getTransactionID();\n            ConnectionIdAttribute connectionId =\n                (ConnectionIdAttribute) ind\n                    .getAttribute(Attribute.CONNECTION_ID);\n            XorPeerAddressAttribute peerAddress =\n                (XorPeerAddressAttribute) ind\n                    .getAttribute(Attribute.XOR_PEER_ADDRESS);\n            peerAddress.setAddress(\n                peerAddress.getAddress(), tranId);\n            logger\n                .finest(\"Received a Connection Attempt Indication with connectionId-\"\n                    + connectionId.getConnectionIdValue()\n                    + \", for peerAddress-\" + peerAddress.getAddress());\n            Socket socket;\n            try\n            {\n                socket =\n                    new Socket(InetAddress.getLocalHost().getHostAddress(),\n                        3478);\n                IceTcpSocketWrapper sockWrapper =\n                    new IceTcpSocketWrapper(socket);\n                this.getTurnStack().addSocket(\n                    sockWrapper);\n                TransportAddress localAddr =\n                    new TransportAddress(sockWrapper.getLocalAddress(),\n                        sockWrapper.getLocalPort(), Transport.TCP);\n                logger.finest(\"New Local TCP socket chosen - \" + localAddr);\n                TransportAddress serverAddress =\n                    new TransportAddress(InetAddress.getLocalHost(), 3478,\n                        Transport.TCP);\n                StunMessageEvent evt = null;\n                try\n                {\n                    Request connectionBindRequest =\n                        MessageFactory.createConnectionBindRequest(connectionId\n                            .getConnectionIdValue());\n                    TransactionID tranID =\n                        TransactionID.createNewTransactionID();\n                    connectionBindRequest.setTransactionID(tranID.getBytes());\n                    if (this.requestSender == null)\n                    {\n                        logger.finest(\"Setting RequestSender\");\n                        this.requestSender =\n                            new BlockingRequestSender(this.getTurnStack(),\n                                localAddr);\n                    }\n                    logger.finest(\"Sending ConnectionBind Request to \"\n                        + serverAddress);\n                    evt = requestSender.sendRequestAndWaitForResponse(\n                        connectionBindRequest, serverAddress);\n                    if (evt != null)\n                    {\n                        Message msg = evt.getMessage();\n                        if (msg.getMessageType() == Message.CONNECTION_BIND_SUCCESS_RESPONSE)\n                        {\n                            logger\n                                .finest(\"Received a ConnectionBind Sucess Response.\");\n                            String myMessage = \"Aakash Garg\";\n                            RawMessage rawMessage =\n                                RawMessage.build(myMessage.getBytes(),\n                                    myMessage.length(), serverAddress,\n                                    localAddr);\n                            try\n                            {\n                                logger\n                                    .finest(\"--------------- Thread will now sleep for 20 sec.\");\n                                Thread.sleep(20 * 1000);\n                            }\n                            catch (InterruptedException e)\n                            {\n                                System.err.println(\"Unable to stop thread\");\n                            }\n                            logger\n                                .finest(\">>>>>>>>>>>> Sending a Test message : \");\n                            byte[] data = myMessage.getBytes();\n                            for (int i = 0; i < data.length; i++)\n                            {\n                                System.out.print(String.format(\n                                    \"%02X, \", data[i]));\n                            }\n                            this.getTurnStack().sendUdpMessage(\n                                rawMessage, serverAddress,\n                                requestSender.getLocalAddress());\n                        }\n                        else\n                        {\n                            logger\n                                .finest(\"Received a ConnectionBind error Response - \"\n                                    + msg.getAttribute(Attribute.ERROR_CODE));\n                        }\n                    }\n                    else\n                    {\n                        System.err\n                            .println(\"No response received to ConnectionBind request\");\n                    }\n                }\n                catch (StunException e)\n                {\n                    logger.finest(\"Unable to send ConnectionBind request\");\n                }\n            }\n            catch (UnknownHostException e)\n            {\n                e.printStackTrace();\n            }\n            catch (IOException e)\n            {\n                e.printStackTrace();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectionBindRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.io.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * The class that would be handling and responding to incoming ConnectionBind\n * requests that are validated and sends a success or error response\n * \n * @author Aakash Garg\n */\npublic class ConnectionBindRequestListener\n    implements RequestListener\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>ConnectionBindRequestListener</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ConnectionBindRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>ConnectionBindrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new ConnectionBindRequestListener\n     * \n     * @param turnStack\n     */\n    public ConnectionBindRequestListener(StunStack stunStack)\n    {\n        this.turnStack = (TurnStack)stunStack;\n    }\n\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CONNECTION_BIND_REQUEST)\n        {\n            Response response = null;\n            Character errorCode = null;\n            \n            TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = evt.getLocalAddress().getTransport();\n            logger.finer(\"Received ConnectBind request \" + evt + \", from \"\n                + clientAddress + \", at \" + serverAddress + \" over \"\n                + transport);\n            ConnectionIdAttribute connectionId = null;\n            if (transport != Transport.TCP)\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n                logger.finest(\"Transport is not TCP.\");\n            }\n            else if (!message.containsAttribute(Attribute.CONNECTION_ID))\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n                logger.finest(\"ConnectionID not found\");\n            }\n            else\n            {\n                connectionId = (ConnectionIdAttribute) message\n                    .getAttribute(Attribute.CONNECTION_ID);\n                logger.finest(\"Requested ConnectionId - \"\n                    + connectionId.getConnectionIdValue());\n                if (!this.turnStack.isUnacknowledged(connectionId\n                    .getConnectionIdValue()))\n                {\n                    errorCode = ErrorCodeAttribute.BAD_REQUEST;\n                    logger.finest(\"ConnectionId-\"\n                        + connectionId.getConnectionIdValue()\n                        + \" not present.\");\n                }\n            }\n            \n            if (errorCode != null)\n            {\n                logger\n                    .finest(\"Creating Connection Bind Error Response, errorCode:\"\n                        + (int) errorCode);\n                response =\n                    MessageFactory\n                        .createConnectionBindErrorResponse(\n                            ErrorCodeAttribute.BAD_REQUEST);\n            }\n            else\n            {\n                // processing logic.\n                FiveTuple clientDataConnTuple =\n                    new FiveTuple(clientAddress, serverAddress, transport);\n                this.turnStack.acknowledgeConnectionId(\n                    connectionId.getConnectionIdValue(), clientDataConnTuple);\n                \n                logger.finest(\"Creating ConnectionBind Success Response\");\n                response = MessageFactory.createConnectionBindResponse();\n            }\n            try\n            {\n                logger.finest(\"Sending ConnectionBind Response to \"\n                    + clientAddress + \" through \" + serverAddress);\n                this.turnStack.sendResponse(\n                    evt.getTransactionID().getBytes(), response, serverAddress,\n                    clientAddress);\n            }\n            catch (StunException e)\n            {\n                logger.finest(\"Unable to send ConnectionBind Response to \"\n                    + clientAddress + \" through \" + serverAddress);\n            }\n            catch (IOException e)\n            {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            }\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /**\n     * Starts this <tt>ConnectionBindRequestListener</tt>. If it is not\n     * currently running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>ConnectionBindRequestListenerr</tt>. A stopped\n     * <tt>ConnectionBindRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/CreatePermissionRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * The class that would be handling and responding to incoming CreatePermission\n * requests that are CreatePermission and sends a success or error response\n * \n * @author Aakash Garg\n */\npublic class CreatePermissionRequestListener\n    implements RequestListener\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>CreatePermissionRequestListener</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(CreatePermissionRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>CreatePermissionrequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new CreatePermissionRequestListener\n     * \n     * @param turnStack\n     */\n    public CreatePermissionRequestListener(StunStack turnStack)\n    {\n        if (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see\n     * org.ice4j.stack.RequestListener#processRequest(org.ice4j.StunMessageEvent\n     * )\n     */\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n//            logger.finer(\"Received request \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.CREATEPERMISSION_REQUEST)\n        {\n            logger.finest(\"Received create permission request \");\n            logger.finest(\"Event tran : \"+evt.getTransactionID());\n            \n            XorPeerAddressAttribute xorPeerAddressAttribute =\n                (XorPeerAddressAttribute) message\n                    .getAttribute(Attribute.XOR_PEER_ADDRESS);\n            if(xorPeerAddressAttribute!=null)\n            {\n                xorPeerAddressAttribute.setAddress(\n                    xorPeerAddressAttribute.getAddress(), \n                    evt.getTransactionID().getBytes());\n            }\n            // we should get multiple xor peer address attributes here.\n            LifetimeAttribute lifetimeAttribute = \n                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);\n            \n            Response response = null;\n            TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = serverAddress.getTransport();\n            FiveTuple fiveTuple =\n                new FiveTuple(clientAddress, serverAddress, transport);\n            \n            Allocation allocation \n                = this.turnStack.getServerAllocation(fiveTuple);\n            \n            Character errorCode = null;\n            if (xorPeerAddressAttribute == null || allocation==null)\n            {\n                errorCode = ErrorCodeAttribute.BAD_REQUEST;\n            }\n            else if (!TurnStack.isIPAllowed(\n                        xorPeerAddressAttribute.getAddress()))\n            {\n                logger.finest(\"Peer Address requested \" \n                        + xorPeerAddressAttribute.getAddress()\n                        +\" \"+TurnStack.isIPAllowed(\n                            xorPeerAddressAttribute.getAddress()));\n                errorCode = ErrorCodeAttribute.FORBIDDEN;\n            }\n            else if (!allocation.canHaveMorePermisions())\n            {\n                errorCode = ErrorCodeAttribute.INSUFFICIENT_CAPACITY;\n            }\n            if(errorCode!=null)\n            {\n                logger.finest(\"Creating error response : \"+(int)errorCode);\n                response = MessageFactory.createCreatePermissionErrorResponse(\n                                errorCode);\n            }\n            else\n            {   \n                logger.finest(\"Creating success response.\");\n                TransportAddress peerAddress \n                    = xorPeerAddressAttribute.getAddress();\n                Permission permission = null;\n                if(lifetimeAttribute!=null)\n                {\n                     permission = new Permission(peerAddress,\n                                         lifetimeAttribute.getLifetime());\n                }\n                else\n                {\n                    permission = new Permission(peerAddress);\n                }\n                \n                logger.finest(\"Peer Address requested \" \n                    + xorPeerAddressAttribute.getAddress()\n                    +\" \"+TurnStack.isIPAllowed(\n                        xorPeerAddressAttribute.getAddress()));\n                allocation.addNewPermission(permission);\n                logger.finest(\"Added permission to allocation.\");\n                response = MessageFactory.createCreatePermissionResponse();\n            }\n            try\n            {\n                turnStack.sendResponse(evt.getTransactionID().getBytes(),\n                    response, evt.getLocalAddress(), evt.getRemoteAddress());\n            }\n            catch (Exception e)\n            {\n                logger.log(Level.INFO, \"Failed to send \" + response\n                    + \" through \" + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n        else\n        {\n            return;\n        }\n    }\n\n    /**\n     * Starts this <tt>CreatePermissionRequestListener</tt>. If it is not\n     * currently running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>CreatePermissionRequestListenerr</tt>. A stopped\n     * <tt>CreatePermissionRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/DataIndicationListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.io.*;\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to handle the incoming Data indications.\n * \n * @author Aakash Garg\n * \n */\npublic class DataIndicationListener extends IndicationListener \n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>DataIndicationListener</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(DataIndicationListener.class.getName());\n\n    /**\n     * parametrised constructor.\n     * \n     * @param turnStack\n     *            the turnStack to set for this class.\n     */\n    public DataIndicationListener(TurnStack turnStack) \n    {\n\tsuper(turnStack);\n    }\n\n    /**\n     * Handles the incoming data indication.\n     * \n     * @param ind\n     *            the indication to handle.\n     * @param alloc\n     *            the allocation associated with message.\n     */\n    @Override\n    public void handleIndication(Indication ind, Allocation alloc) \n    {\n\tif (ind.getMessageType() == Message.DATA_INDICATION) \n\t{\n\t    logger.finest(\"Received a Data Indication message.\");\n\t    byte[] tran = ind.getTransactionID();\n\n\t    XorPeerAddressAttribute xorPeerAddress \n\t    \t= (XorPeerAddressAttribute) ind\n\t\t    .getAttribute(Attribute.XOR_PEER_ADDRESS);\n\t    xorPeerAddress.setAddress(xorPeerAddress.getAddress(), tran);\n\t    DataAttribute data = (DataAttribute) ind\n\t\t    .getAttribute(Attribute.DATA);\n\n\t    TransportAddress peerAddr = xorPeerAddress.getAddress();\n\t    try \n\t    {\n\t\tString line = new String(data.getData(), \"UTF-8\");\n//\t\tSystem.out.println(line);\n\t\tlogger.finest(\"Data Indiaction message from  \" + peerAddr\n\t\t\t+ \" is \" + line);\n/*\t\tSystem.out.println(\"Received a Data indiction from \" + peerAddr\n\t\t\t+ \", message : \" + line);\n*/\t    } catch (UnsupportedEncodingException e) \n{\n\t\tSystem.err.println(\"Unable to convert to String!\");\n\t    }\n\t}\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/PeerTcpConnectEventListner.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.ice4j.StunException;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.socket.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to handle events when Peer tries to establish a TCP connection to a\n * Server Socket (generally Relay Address).\n * \n * @author Aakash Garg\n * \n */\npublic class PeerTcpConnectEventListner\n    implements TcpConnectEventListener\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>FiveTuple</tt> class and its\n     * instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(PeerTcpConnectEventListner.class.getName());\n\n    private final TurnStack turnStack;\n\n    public PeerTcpConnectEventListner(TurnStack turnStack)\n    {\n        this.turnStack = turnStack;\n    }\n\n    @Override\n    public void onConnect(TcpConnectEvent event)\n    {\n        logger.setLevel(Level.FINEST);\n        logger.finest(\"Received a connect event src:\" + event.getLocalAdress()\n            + \", dest:\" + event.getRemoteAdress());\n        Allocation allocation =\n            this.turnStack.getServerAllocation(event.getLocalAdress());\n        if (allocation == null)\n        {\n            logger.finest(\"Allocation not found for relay : \"\n                + event.getLocalAdress());\n        }\n        else if (allocation.isPermitted(event.getRemoteAdress()))\n        {\n            try\n            {\n                ConnectionIdAttribute connectionId =\n                    AttributeFactory.createConnectionIdAttribute();\n                logger.finest(\"Created ConnectionId - \"\n                    + connectionId.getConnectionIdValue() + \" for client \"\n                    + allocation.getClientAddress());\n                TransactionID tranID = TransactionID.createNewTransactionID();\n                Indication connectionAttemptIndication =\n                    MessageFactory.createConnectionAttemptIndication(\n                        connectionId.getConnectionIdValue(),\n                        event.getRemoteAdress(), tranID.getBytes());\n                this.turnStack.addUnAcknowlededConnectionId(\n                    connectionId.getConnectionIdValue(),\n                    event.getRemoteAdress(), allocation);\n                logger.finest(\"Sending Connection Attempt Indication.\");\n                this.turnStack.sendIndication(\n                    connectionAttemptIndication, allocation.getClientAddress(),\n                    allocation.getServerAddress());\n            }\n            catch (StunException e)\n            {\n                logger\n                    .finest(\"Unable to send Connection Attempt Indiacation to \"\n                        + allocation.getClientAddress());\n            }\n        }\n        else\n        {\n            logger.finest(\"permission not installed for - \"\n                + event.getRemoteAdress());\n        }\n        // this.turnStack.add\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/RefreshRequestListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * The class that would be handling and responding to incoming Refresh requests\n * that are validated and sends a success or error response\n * \n * @author Aakash Garg\n */\npublic class RefreshRequestListener\n    implements RequestListener\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>RefreshRequestListener</tt> class and\n     * its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(RefreshRequestListener.class.getName());\n\n    private final TurnStack turnStack;\n\n    /**\n     * The indicator which determines whether this\n     * <tt>RefreshRequestListener</tt> is currently started.\n     */\n    private boolean started = false;\n\n    /**\n     * Creates a new RefreshRequestListener\n     * \n     * @param turnStack\n     */\n    public RefreshRequestListener(StunStack turnStack)\n    {\n        if (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    /**\n     * (non-Javadoc)\n     * \n     * @see org.ice4j.stack.RequestListener#processRequest(org.ice4j.StunMessageEvent)\n     */\n    @Override\n    public void processRequest(StunMessageEvent evt)\n        throws IllegalArgumentException\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);            \n//            logger.finer(\"Received request \" + evt);\n        }\n        Message message = evt.getMessage();\n        if (message.getMessageType() == Message.REFRESH_REQUEST)\n        {\n            logger.finer(\"Received refresh request \" + evt);\n\n            LifetimeAttribute lifetimeAttribute =\n                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);\n            \n            Response response = null;\n            TransportAddress clientAddress = evt.getRemoteAddress();\n            TransportAddress serverAddress = evt.getLocalAddress();\n            Transport transport = serverAddress.getTransport();\n            FiveTuple fiveTuple =\n                new FiveTuple(clientAddress, serverAddress, transport);\n            \n            Allocation allocation =\n                this.turnStack.getServerAllocation(fiveTuple);\n            if (allocation != null)\n            {\n                if (lifetimeAttribute != null)\n                {\n\t\t    logger.finest(\"Refreshing allocation with relay addr \"\n\t\t\t    + allocation.getRelayAddress() + \" with lifetime \"\n\t\t\t    + lifetimeAttribute.getLifetime());\n                    allocation.refresh(lifetimeAttribute.getLifetime());\n                    response = MessageFactory.createRefreshResponse(\n                            (int) allocation.getLifetime());\n                }\n                else\n                {\n\t\t    logger.finest(\"Refreshing allocation with relay addr \"\n\t\t\t    + allocation.getRelayAddress()\n\t\t\t    + \" with default lifetime\");\n                    allocation.refresh();\n                    response = MessageFactory.createRefreshResponse(\n                            (int) allocation.getLifetime());\n                }\n            }\n            else\n            {\n        \tlogger.finest(\"Allocation mismatch error\");\n                response = MessageFactory.createRefreshErrorResponse(\n                            ErrorCodeAttribute.ALLOCATION_MISMATCH);\n            }\n            try\n            {\n                turnStack.sendResponse(evt.getTransactionID().getBytes(),\n                    response, evt.getLocalAddress(), evt.getRemoteAddress());\n            }\n            catch (Exception e)\n            {\n                logger.log(Level.INFO, \"Failed to send \" + response\n                    + \" through \" + evt.getLocalAddress(), e);\n                // try to trigger a 500 response although if this one failed,\n                throw new RuntimeException(\"Failed to send a response\", e);\n            }\n        }\n        else\n        {\n            return;\n        }\n\n    }\n\n    /**\n     * Starts this <tt>RefreshRequestListener</tt>. If it is not currently\n     * running, does nothing.\n     */\n    public void start()\n    {\n        if (!started)\n        {\n            turnStack.addRequestListener(this);\n            started = true;\n        }\n    }\n\n    /**\n     * Stops this <tt>RefreshRequestListenerr</tt>. A stopped\n     * <tt>ValidatedRequestListenerr</tt> can be restarted by calling\n     * {@link #start()} on it.\n     */\n    public void stop()\n    {\n        turnStack.removeRequestListener(this);\n        started = false;\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/SendIndicationListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.listeners;\n\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to handle the incoming Send indications.\n * \n * @author Aakash Garg\n * \n */\npublic class SendIndicationListener extends IndicationListener \n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>SendIndicationListener</tt>\n     * class and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(SendIndicationListener.class.getName());\n\n    /**\n     * parametrised constructor.\n     * \n     * @param turnStack\n     *            the turnStack to set for this class.\n     */\n    public SendIndicationListener(TurnStack turnStack) \n    {\n\tsuper(turnStack);\n    }\n\n    /**\n     * Handles the incoming send indication.\n     * \n     * @param ind\n     *            the indication to handle.\n     * @param alloc\n     *            the allocation associated with message.\n     */\n    @Override\n    public void handleIndication(Indication ind, Allocation alloc) \n    {\n\tif(ind.getMessageType()==Message.SEND_INDICATION)\n\t{\n\t    logger.finest(\"Received a Send Indication message.\");\n\t    byte[] tran = ind.getTransactionID();\n\t    XorPeerAddressAttribute xorPeerAddress\n\t    \t= (XorPeerAddressAttribute) ind\n\t    \t\t.getAttribute(Attribute.XOR_PEER_ADDRESS);\n\t    xorPeerAddress.setAddress(xorPeerAddress.getAddress(), tran);\n\t    DataAttribute data \n\t    \t= (DataAttribute) ind.getAttribute(Attribute.DATA);\n\t    TransportAddress peerAddr = xorPeerAddress.getAddress();\n\t    if(alloc!=null && alloc.isPermitted(peerAddr))\n\t    {\n\t\tRawMessage udpMessage = RawMessage.build(data.getData(),\n\t\t\tdata.getDataLength(), peerAddr, alloc.getRelayAddress());\n\t\ttry \n\t\t{\n\t\t    this.getTurnStack().sendUdpMessage(udpMessage, peerAddr,\n\t\t\t    alloc.getRelayAddress());\n\t\t    logger.finest(\"Sent SendIndiaction to \" + peerAddr\n\t\t\t    + \" from \" + alloc.getRelayAddress());\n\t\t} catch (StunException e) {\n\t\t    System.err.println(\"Unable to send message.\");\n\t\t}\n\t    }\n\t    // else silently ignore the indication.\n\t}\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/IceTcpEventizedServerSockerWrapper.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.socket;\n\nimport java.io.IOException;\nimport java.net.*;\nimport java.util.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.ice.*;\nimport org.ice4j.socket.*;\n\n/**\n * Class for eventized TCP server Socket where event is when someone tries to\n * connect to the given server Socket of the class.\n * \n * @author Aakash Garg\n * \n */\npublic class IceTcpEventizedServerSockerWrapper\n    extends IceSocketWrapper\n    implements TcpConnectEventGenerator\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>LocalCandidate</tt> class and its\n     * instances for logging output.\n     */\n    private static Logger logger = Logger\n        .getLogger(IceTcpEventizedServerSockerWrapper.class.getName());\n\n    /**\n     * Thread that will wait new connections.\n     */\n    private Thread acceptThread = null;\n\n    /**\n     * The wrapped TCP ServerSocket.\n     */\n    private final ServerSocket serverSocket;\n\n    /**\n     * If the socket is still listening.\n     */\n    private boolean isRun = false;\n\n    private TcpConnectEventListener listener;\n\n    /**\n     * STUN stack.\n     */\n    private final Component component;\n\n    /**\n     * List of TCP client sockets.\n     */\n    private final List<Socket> sockets = new ArrayList<Socket>();\n\n    public IceTcpEventizedServerSockerWrapper(ServerSocket serverSocket,\n        Component component)\n    {\n        this.serverSocket = serverSocket;\n        this.component = component;\n        acceptThread = new ThreadAccept();\n        acceptThread.start();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void send(DatagramPacket p) throws IOException\n    {\n        System.err.println(\"Send called in IceTcpServerSocketWrapper.\");\n        /* Do nothing for the moment */\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void receive(DatagramPacket p) throws IOException\n    {\n        System.err.println(\"Receive called in IceTcpServerSocketWrapper.\");\n        /* Do nothing for the moment */\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void close()\n    {\n        try\n        {\n            isRun = false;\n            serverSocket.close();\n            for (Socket s : sockets)\n            {\n                s.close();\n            }\n        }\n        catch (IOException e)\n        {\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public InetAddress getLocalAddress()\n    {\n        return serverSocket.getInetAddress();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public int getLocalPort()\n    {\n        return serverSocket.getLocalPort();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public SocketAddress getLocalSocketAddress()\n    {\n        return serverSocket.getLocalSocketAddress();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Socket getTCPSocket()\n    {\n        if (sockets.size() > 0)\n        {\n            return sockets.get(0);\n        }\n\n        return null;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public DatagramSocket getUDPSocket()\n    {\n        return null;\n    }\n\n    @Override\n    public void setEventListener(TcpConnectEventListener listener)\n    {\n        this.listener = listener;\n    }\n\n    @Override\n    public void removeEventListener()\n    {\n        this.listener = null;\n    }\n\n    @Override\n    public void fireConnectEvent(TcpConnectEvent event)\n    {\n        if (this.listener != null)\n            this.listener.onConnect(event);\n        else\n            logger.finest(\"Listener not registered\");\n    }\n\n    /**\n     * Thread that will wait for new TCP connections.\n     * \n     */\n    private class ThreadAccept\n        extends Thread\n    {\n        /**\n         * Thread entry point.\n         */\n        @Override\n        public void run()\n        {\n            isRun = true;\n\n            while (isRun)\n            {\n                try\n                {\n                    Socket tcpSocket = serverSocket.accept();\n\n                    if (tcpSocket != null)\n                    {\n                        MultiplexingSocket multiplexingSocket =\n                            new MultiplexingSocket(tcpSocket);\n                        component.getParentStream().getParentAgent()\n                            .getStunStack().addSocket(\n                                new IceTcpSocketWrapper(multiplexingSocket));\n\n                        sockets.add(multiplexingSocket);\n                        String[] serverIpPort =\n                            serverSocket.getLocalSocketAddress().toString()\n                                .replaceAll(\n                                    \"/\", \"\").split(\n                                    \":\");\n                        TransportAddress localAddr =\n                            new TransportAddress(InetAddress.getLocalHost(),\n                                Integer.parseInt(serverIpPort[1]),\n                                Transport.TCP);\n                        \n                        String[] remoteIpPort =\n                            tcpSocket.getRemoteSocketAddress().toString()\n                                .replaceAll(\n                                    \"/\", \"\").split(\n                                    \":\");\n                        TransportAddress remoteAddr =\n                            new TransportAddress(remoteIpPort[0],\n                                Integer.parseInt(remoteIpPort[1]),\n                                Transport.TCP);\n                        logger.finest(\"Connection Request from \"+remoteAddr+\" to \"+localAddr);\n                        TcpConnectEvent event =\n                            new TcpConnectEvent(localAddr, remoteAddr);\n                        IceTcpEventizedServerSockerWrapper.this\n                            .fireConnectEvent(event);\n                    }\n                }\n                catch (IOException e)\n                {\n                    logger.info(\"Failed to accept TCP socket \" + e);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEvent.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.socket;\n\nimport org.ice4j.TransportAddress;\n\n/**\n * Represents the TCP connect event on the Server Socket.\n * \n * @author Aakash Garg\n * \n */\npublic class TcpConnectEvent\n{\n    private final TransportAddress localAdress;\n    \n    private final TransportAddress remoteAdress;\n\n    /**\n     * @param localAdress\n     * @param remoteAdress\n     */\n    public TcpConnectEvent(TransportAddress localAdress,\n        TransportAddress remoteAdress)\n    {\n        this.localAdress = localAdress;\n        this.remoteAdress = remoteAdress;\n    }\n\n    public TransportAddress getLocalAdress()\n    {\n        return localAdress;\n    }\n\n    public TransportAddress getRemoteAdress()\n    {\n        return remoteAdress;\n    }   \n\n    \n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEventGenerator.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.socket;\n\n/**\n * Represents the source of generating the TCP connect events.\n * \n * @author Aakash Garg\n * \n */\npublic interface TcpConnectEventGenerator\n{\n    public void setEventListener(TcpConnectEventListener listener);\n    \n    public void removeEventListener();\n    \n    public void fireConnectEvent(TcpConnectEvent event);\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEventListener.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.socket;\n\n/**\n * Represents the TCP Connect Event Listener.\n * \n * @author Aakash Garg.\n * \n */\npublic interface TcpConnectEventListener\n{\n    public void onConnect(TcpConnectEvent event);\n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/Allocation.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.logging.Logger;\n\nimport org.ice4j.Transport;\nimport org.ice4j.TransportAddress;\n\n/**\n * This class is an implementation of Allocations in TURN server.\n * \n * @author Aakash Garg\n * \n */\npublic class Allocation\n{\n    /**\n     * Our class logger.\n     */\n    private static final Logger logger = Logger.getLogger(Allocation.class\n        .getName());\n\n    /**\n     * represents the relay address associated with this Allocation.\n     */\n    private final TransportAddress relayAddress;\n\n    /**\n     * Represents the FiveTuple associated with this Allocation.\n     */\n    private final FiveTuple fiveTuple;\n\n    /**\n     * Represents the username associated with this Allocation.\n     */\n    private final String username;\n\n    /**\n     * represents the password associated with this Allocation.\n     */\n    private final String password;\n\n    /**\n     * The time in milliseconds when the Allocation will expire.\n     */\n    private long expirationTime = -1;\n\n    /**\n     * Determines whether or not the Allocation has expired.\n     */\n    private boolean expired = false;\n\n    /**\n     * The default lifetime allowed for a Allocation.\n     */\n    public static final long DEFAULT_LIFETIME = 10 * 60 * 1000;\n\n    /**\n     * The max lifetime allowed for a Allocation.\n     */\n    public static final long MAX_LIFETIME = 60 * 60 * 1000;\n\n    /**\n     * The maximum no of Permissions per Allocation.\n     */\n    public static final int MAX_PERMISSIONS = 10;\n\n    /**\n     * The Maximum no of ChannelBinds per Allocation.\n     */\n    public static final int MAX_CHANNELBIND = 10;\n\n    /**\n     * The <tt>Thread</tt> which expires the <tt>Permission</tt>s of this\n     * <tt>Allocation</tt> and removes them from {@link #permissions}.\n     */\n    private Thread permissionExpireThread;\n\n    /**\n     * Represents the permissions associated with peerAddress IP installed for\n     * this Allocation.\n     */\n    private final HashMap<TransportAddress, Permission> permissions =\n        new HashMap<TransportAddress, Permission>();\n\n    /**\n     * The <tt>Thread</tt> which expires the <tt>ChannelBind</tt>s of this\n     * <tt>Allocation</tt> and removes them from {@link #channelBindings}.\n     */\n    private Thread channelBindExpireThread;\n\n    /**\n     * Represents the Channel Bindings associated with this Allocation.\n     */\n    private final HashMap<Character, ChannelBind> channelBindings =\n        new HashMap<Character, ChannelBind>();\n\n    /**\n     * Contains the mapping of peerAdress of ChannelBinds to Channelno. This is\n     * used to check the peerAddress while creating new Permissions and\n     * ChannelBinds.\n     */\n    private final HashMap<TransportAddress, Character> peerToChannelMap =\n        new HashMap<TransportAddress, Character>();\n\n    /**\n     * Maps one-to-one from ConnecionID to Data Connection.\n     */\n    private final HashMap<Integer,FiveTuple> connIdToDataConnMap\n         = new HashMap<Integer,FiveTuple>();\n    \n    /**\n     * Maps one-to-one from ConnecionID to Peer TCP Connection.\n     */\n    private final HashMap<Integer,FiveTuple> connIdToPeerConnMap\n        = new HashMap<Integer,FiveTuple>();\n    \n    /**\n     * Constructor to instantiate an Allocation without a username and password.\n     * \n     * @param relayAddress the realyAddress associated with this Allocation.\n     * @param fiveTuple the fiveTuple associated with this Allocation.\n     */\n    public Allocation(  TransportAddress relayAddress, \n                        FiveTuple fiveTuple)\n    {\n        this(relayAddress, fiveTuple, null, null);\n    }\n\n    /**\n     * Constructor to instantiate an Allocation without a username and password\n     * with the lifetime value.\n     * \n     * @param relayAddress the realyAddress associated with this Allocation.\n     * @param fiveTuple the fiveTuple associated with this Allocation.\n     * @param lifetime the lifetime for this Allocation.\n     */\n    public Allocation(  TransportAddress relayAddress, \n                        FiveTuple fiveTuple,\n                        long lifetime)\n    {\n        this(relayAddress, fiveTuple, null, null, lifetime);\n    }\n\n    /**\n     * Constructor to instantiate an Allocation with given relayAddress,\n     * fiveTuple, username, passowrd and with default lifetime value.\n     * \n     * @param relayAddress the realyAddress associated with this Allocation.\n     * @param fiveTuple the fiveTuple associated with this Allocation.\n     * @param username the username associated with this Allocation.\n     * @param password the password associated with this Allocation.\n     */\n    public Allocation(  TransportAddress relayAddress, \n                        FiveTuple fiveTuple,\n                        String username, \n                        String password)\n    {\n        this(relayAddress, fiveTuple, username, password,\n            Allocation.DEFAULT_LIFETIME);\n    }\n\n    /**\n     * Constructor to instantiate an Allocation with given relayAddress,\n     * fiveTuple, username, passowrd and with default lifetime value.\n     * \n     * @param relayAddress the realyAddress associated with this Allocation.\n     * @param fiveTuple the fiveTuple associated with this Allocation.\n     * @param username the username associated with this Allocation.\n     * @param password the password associated with this Allocation.\n     * @param lifetime the lifetime for this allocation.\n     */\n    public Allocation(  TransportAddress relayAddress, \n                        FiveTuple fiveTuple,\n                        String username, \n                        String password, \n                        long lifetime)\n    {\n        this.relayAddress = relayAddress;\n        this.fiveTuple = fiveTuple;\n        this.username = username;\n        this.password = password;\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * returns the fiveTuple associated with this Allocation.\n     */\n    public FiveTuple getFiveTuple()\n    {\n        return this.fiveTuple;\n    }\n\n    /**\n     * Returns the relayAddress associated with this Allocation.\n     */\n    public TransportAddress getRelayAddress()\n    {\n        return this.relayAddress;\n    }\n\n    /**\n     * Returns the clientAddress associated with this Allocation.\n     * The client address who instianted this allocation.\n     */\n    public TransportAddress getClientAddress()\n    {\n        return this.getFiveTuple().getClientTransportAddress();\n    }    \n    \n    /**\n     * Returns the serverAddress associated with this Allocation.\n     * The serverAddress on which this allocation request is received.\n     */\n    public TransportAddress getServerAddress()\n    {\n        return this.getFiveTuple().getServerTransportAddress();\n    }\n    \n    /**\n     * Returns the Client Data Connection corresponding to Connection Id for\n     * which ConnectionBind Request has been received.\n     * \n     * @param connectionId the ConnectionId for which Client Data Connection is\n     *            to be returned.\n     * @return Client Data Connection if exists else null.\n     */\n    public FiveTuple getDataConnection(int connectionId){\n        return this.connIdToDataConnMap.get(connectionId);\n    }\n    \n    /**\n     * Returns the Peer TCP Data Connection corresponding to Connection Id for\n     * which ConnectionBind Request has been received.\n     * \n     * @param connectionId the ConnectionId for which Peer TCP Data Connection is\n     *            to be returned.\n     * @return Peer TCP Data Connection if exists else null.\n     */\n    public FiveTuple getPeerTCPConnection(int connectionId){\n        return this.connIdToPeerConnMap.get(connectionId);\n    }\n\n    /**\n     * Adds the Connection Id with corresponding Client Data Connection to for\n     * which ConnectionBind Request has been received.\n     * \n     * @param connectionId the ConnectionId.\n     * @param clientDataConn Client Data Connection to corresponding\n     *            ConnectionId.\n     */\n    public void addDataConnection(int connectionId, FiveTuple clientDataConn)\n    {\n        this.connIdToDataConnMap.put(\n            connectionId, clientDataConn);\n    }\n\n    /**\n     * Adds the Connection Id corresponding to Peer TCP Data Connection for\n     * which ConnectionBind Request has been received.\n     * \n     * @param connectionId the ConnectionId.\n     * @param peerDataConn Peer TCP Data Connection to corresponding\n     *            ConnectionId.\n     */\n    public void addPeerTCPConnection(int connectionId, FiveTuple peerDataConn)\n    {\n        this.connIdToPeerConnMap.put(connectionId,peerDataConn);\n    }\n    \n    /**\n     * Removes the Client Data Connection with corresponding to Connection Id.\n     * \n     * @param connectionId the ConnectionId corresponding to Client Data\n     *            Connection.\n     */\n    public void removeDataConnection(int connectionId)\n    {\n        this.connIdToDataConnMap.remove(connectionId);\n    }\n\n    /**\n     * Removes the Peer TCP Data Connection corresponding to Connection Id.\n     * \n     * @param connectionId the ConnectionId corresponding to Client Data\n     *            Connection.\n     */\n    public void removePeerTCPConnection(int connectionId)\n    {\n        this.connIdToPeerConnMap.remove(connectionId);\n    }    \n    \n    /**\n     * Returns the lifetime associated with this Allocation. If the allocation\n     * is expired it returns 0.\n     */\n    public long getLifetime()\n    {\n        if (!isExpired())\n        {\n            return (this.expirationTime - System.currentTimeMillis());\n        }\n        else\n        {\n            return 0;\n        }\n    }\n\n    /**\n     * Sets the time to expire in milli-seconds for this allocation. Max\n     * lifetime can be Allocation.MAX_LIFEIME.\n     * \n     * @param lifetime the lifetime for this Allocation.\n     */\n    public void setLifetime(long lifetime)\n    {\n        synchronized (this)\n        {\n            this.expirationTime = System.currentTimeMillis() \n                + Math.min(lifetime * 1000, Allocation.MAX_LIFETIME);\n        }\n    }\n\n    /**\n     * Refreshes the allocation with the DEFAULT_LIFETIME value.\n     */\n    public void refresh()\n    {\n        this.setLifetime(Allocation.DEFAULT_LIFETIME);\n    }\n\n    /**\n     * refreshes the allocation with given lifetime value.\n     * \n     * @param lifetime the required lifetime of allocation.\n     */\n    public void refresh(int lifetime)\n    {\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * Start the Allocation. This launches the countdown to the moment the\n     * Allocation would expire.\n     */\n    public synchronized void start()\n    {\n        synchronized (this)\n        {\n            if (expirationTime == -1)\n            {\n                expired = false;\n                expirationTime = DEFAULT_LIFETIME + System.currentTimeMillis();\n            }\n            else\n            {\n                throw new IllegalStateException(\n                    \"Allocation has already been started!\");\n            }\n        }\n    }\n    \n    /**\n     * Determines whether this <tt>Allocation</tt> is expired now.\n     * \n     * @return <tt>true</tt> if this <tt>Allocation</tT> is expired now;\n     *         otherwise, <tt>false</tt>\n     */\n    public boolean isExpired()\n    {\n        return isExpired(System.currentTimeMillis());\n    }\n\n    /**\n     * Expires the Allocation. Once this method is called the Allocation is\n     * considered terminated.\n     */\n    public synchronized void expire()\n    {\n        expired = true;\n        /*\n         * TurnStack has a background Thread running with the purpose of\n         * removing expired Allocations.\n         */\n    }\n\n    /**\n     * Determines whether this <tt>Allocation</tt> will be expired at a specific\n     * point in time.\n     * \n     * @param now the time in milliseconds at which the <tt>expired</tt> state\n     *            of this <tt>Allocation</tt> is to be returned\n     * @return <tt>true</tt> if this <tt>Allocation</tt> will be expired at the\n     *         specified point in time; otherwise, <tt>false</tt>\n     */\n    public synchronized boolean isExpired(long now)\n    {\n        if (expirationTime == -1)\n            return false;\n        else if (expirationTime < now)\n            return true;\n        else\n            return expired;\n    }\n\n    /**\n     * Adds a new Permission for this Allocation.\n     * \n     * @param peerIP the peer IP address foe which to create this permission to\n     *            be added to this allocation.\n     */\n    public void addNewPermission(TransportAddress peerIP)\n    {\n        TransportAddress peerIp =\n            new TransportAddress(peerIP.getAddress(), 0, Transport.UDP);\n        Permission permission = new Permission(peerIP);\n        this.addNewPermission(permission);\n    }\n\n    /**\n     * Adds a new Permission for this Allocation.\n     * \n     * @param permission the permission to be added to this allocation.\n     */\n    public void addNewPermission(Permission permission)\n    {\n        TransportAddress peerAddr =\n            new TransportAddress(permission.getIpAddress().getAddress(), 0,\n                Transport.UDP);\n        if (this.permissions.containsKey(peerAddr))\n        {\n            this.permissions.get(permission.getIpAddress()).refresh();\n        }\n        else if (!this.canHaveMorePermisions())\n        {\n            return;\n        }\n        else\n        {\n            this.permissions.put(\n                permission.getIpAddress(), permission);\n            maybeStartPermissionExpireThread();\n        }\n    }\n\n    /**\n     * Binds a new Channel to this Allocation.\n     * If an existing ChannelBind is found it is refreshed\n     * else a new ChannelBind and permission is added.\n     * \n     * @param channelBind the channelBind to be added to this allocation.\n     * @throws IllegalArgumentException if the channelNo of the channelBind to\n     *             be added is already occupied.\n     */\n    public void addChannelBind(ChannelBind channelBind)\n    {\n        TransportAddress peerAddr =\n            new TransportAddress(\n                    channelBind.getPeerAddress().getAddress(),\n                    0, \n                    Transport.UDP);\n        if (isBadChannelRequest(channelBind))\n        {\n            throw new IllegalArgumentException(\"400: BAD REQUEST\");\n        }\n        else if(!channelBindings.containsKey(channelBind.getChannelNo()) \n               && !peerToChannelMap.containsKey(channelBind.getPeerAddress()))\n        {\n            synchronized(this.channelBindings)\n            {\n                this.channelBindings.put(   channelBind.getChannelNo(),\n                                            channelBind);\n            }\n            synchronized(this.peerToChannelMap)\n            {\n                this.peerToChannelMap.put(\n                    channelBind.getPeerAddress(), channelBind.getChannelNo());\n            }\n        }\n        else\n        {\n            synchronized(this.channelBindings)\n            {\n                this.channelBindings.get(channelBind.getChannelNo()).refresh();\n            }\n        }\n        this.addNewPermission(peerAddr);\n        maybeStartChannelBindExpireThread();\n    }\n\n    /**\n     * Determines whether the ChannelBind request is a BAD request or not.\n     * A request is BAD when the same client sends a ChannelBind Request and\n     * channel no or peerAddress coincides with existing channel bindings.\n     * A request is not bad if the channel no and peerAddress in the ChannelBind\n     * request are same as that in current mapping.\n     * \n     * @param channelBind the channelBind request to validate.\n     * @return true if request is a BAD request.\n     */\n    public boolean isBadChannelRequest(ChannelBind channelBind)\n    {\n        boolean hasChannelNo =\n            this.channelBindings.containsKey(channelBind.getChannelNo());\n        boolean hasPeerAddr =\n            this.peerToChannelMap.containsKey(channelBind.getPeerAddress());\n        if(hasChannelNo && hasPeerAddr)\n        {\n            if (this.channelBindings.get(\n                channelBind.getChannelNo()).equals(\n                    channelBind.getPeerAddress()))\n            {\n                return false;\n            }\n      }\n      else if(!hasChannelNo && !hasPeerAddr)\n      {\n          return false;\n      }\n        return true;\n    }\n    \n    /**\n     * Removes the channelBind associated with this channlNo from this\n     * allocation.\n     * \n     * @param channelNo the channelNo for which the ChannelBind to delete.\n     * @return the ChannnelBindingf associated with this channelNo.\n     */\n    public ChannelBind removeChannelBind(char channelNo)\n    {\n        ChannelBind channelBind = null;\n        synchronized (this.channelBindings)\n        {\n            channelBind = this.channelBindings.remove(channelNo);\n        }\n        return channelBind;\n    }\n\n    /**\n     * Checks if the Permission is installed for the peerAddress. The port value\n     * is ignored.\n     * \n     * @param peerAddress\n     *            the peerAddress for which to check permission.\n     * @return true if permission is installed for peerAddress else false.\n     */\n    public boolean isPermitted(TransportAddress peerAddress)\n    {\n        peerAddress =\n            new TransportAddress(peerAddress.getAddress(), 0,\n                peerAddress.getTransport());\n        if (this.permissions.containsKey(peerAddress))\n        {\n            return true;\n        }\n        return false;\n    }\n    \n    /**\n     * Checks if the specified channel no is binded to this allocation.\n     * \n     * @param channelNo\n     *            the channel number to check.\n     * @return true if the specified channel no. is installed for this\n     *         allocation.\n     */\n    public boolean containsChannel(char channelNo)\n    {\n\treturn this.channelBindings.containsKey(channelNo);\n    }\n\n    /**\n     * Gets the channelNO for the specified peerAddress.\n     * @param peerAddress the peerAddress for which to get the channel.\n     * @return channelNo is channelNo is found, else 0x1000.\n     */\n    public char getChannel(TransportAddress peerAddress)\n    {\n\tchar val = 0x1000;\n\tif(this.peerToChannelMap.containsKey(peerAddress))\n\t{\n\t    return this.peerToChannelMap.get(peerAddress);\n\t}\n\treturn val;\n    }\n    \n    /**\n     * Gets the peerAddress associated with specified channelNo.\n     * \n     * @param channelNo\n     *            the channel no for which to get the peerAddress.\n     * @return peerAddress the peerAddress associated with the channelNo in this\n     *         allocation.\n     */\n    public TransportAddress getPeerAddr(char channelNo)\n    {\n\tChannelBind cb = this.channelBindings.get(channelNo);\n\tif(cb!=null)\n\t{\n\t    return cb.getPeerAddress();\n\t}\n\treturn null;\n    }\n    \n    /**\n     * Determines if more permissions can be added to this allocation.\n     * \n     * @return true if no of permissions are less than maximum allowed\n     *         permissions per Allocation.\n     */\n    public boolean canHaveMorePermisions()\n    {\n        return (this.permissions.size() < MAX_PERMISSIONS);\n    }\n\n    /**\n     * Determines if more channels can be added to this allocation.\n     * \n     * @return true if no of channels are less than maximum allowed channels per\n     *         Allocation.\n     */\n    public boolean canHaveMoreChannels()\n    {\n        return (this.channelBindings.size() < MAX_CHANNELBIND);\n    }\n\n    /**\n     * Initialises and starts {@link #channelBindExpireThread} if necessary.\n     */\n    public void maybeStartChannelBindExpireThread()\n    {\n        synchronized (channelBindings)\n        {\n            if (!channelBindings.isEmpty() && (channelBindExpireThread == null))\n            {\n                Thread t = new Thread()\n                {\n                    @Override\n                    public void run()\n                    {\n                        runInAllocationChannelBindExpireThread();\n                    }\n                };\n\n                t.setDaemon(true);\n                t.setName(getClass().getName() + \".channelBindExpireThread\");\n\n                boolean started = false;\n\n                channelBindExpireThread = t;\n                try\n                {\n                    t.start();\n                    started = true;\n                }\n                finally\n                {\n                    if (!started && (channelBindExpireThread == t))\n                        channelBindExpireThread = null;\n                }\n            }\n        }\n    }\n\n    /**\n     * Runs in {@link #channelBindExpireThread} and expires the\n     * <tt>ChannelBind</tt>s of this <tt>Allocation</tt> and removes them from\n     * {@link #channelBindingings}.\n     */\n    private void runInAllocationChannelBindExpireThread()\n    {\n        try\n        {\n            long idleStartTime = -1;\n\n            do\n            {\n                synchronized (channelBindings)\n                {\n                    try\n                    {\n                        channelBindings.wait(ChannelBind.MAX_LIFETIME);\n                    }\n                    catch (InterruptedException ie)\n                    {\n                    }\n\n                    /*\n                     * Is the current Thread still designated to expire the\n                     * ChannelBinds of this Allocation?\n                     */\n                    if (Thread.currentThread() != channelBindExpireThread)\n                        break;\n\n                    long now = System.currentTimeMillis();\n\n                    /*\n                     * Has the current Thread been idle long enough to merit\n                     * disposing of it?\n                     */\n                    if (channelBindings.isEmpty())\n                    {\n                        if (idleStartTime == -1)\n                            idleStartTime = now;\n                        else if (now - idleStartTime > 60 * 1000)\n                            break;\n                    }\n                    else\n                    {\n                        // Expire the ChannelBinds of this Allocation.\n\n                        idleStartTime = -1;\n\n                        for (Iterator<ChannelBind> i =\n                            channelBindings.values().iterator(); i.hasNext();)\n                        {\n                            ChannelBind channelBind = i.next();\n\n                            if (channelBind == null)\n                            {\n                                i.remove();\n                            }\n                            else if (channelBind.isExpired(now))\n                            {\n                                logger.finer(\"ChannelBind \" + channelBind\n                                    + \" expired\");\n                                i.remove();\n                                this.peerToChannelMap.remove(\n                                    channelBind.getPeerAddress());\n                                channelBind.expire();\n                            }\n                        }\n                    }\n                }\n            }\n            while (true);\n        }\n        finally\n        {\n            synchronized (channelBindings)\n            {\n                if (channelBindExpireThread == Thread.currentThread())\n                    channelBindExpireThread = null;\n                /*\n                 * If channelBindExpireThread dies unexpectedly and yet it is\n                 * still necessary, resurrect it.\n                 */\n                if (channelBindExpireThread == null)\n                    maybeStartChannelBindExpireThread();\n            }\n        }\n    }\n\n    /**\n     * Initialises and starts {@link #permissionExpireThread} if necessary.\n     */\n    public void maybeStartPermissionExpireThread()\n    {\n        synchronized (permissions)\n        {\n            if (!permissions.isEmpty() && (permissionExpireThread == null))\n            {\n                Thread t = new Thread()\n                {\n                    @Override\n                    public void run()\n                    {\n                        runInAllocationPermissionExpireThread();\n                    }\n                };\n\n                t.setDaemon(true);\n                t.setName(getClass().getName() + \".permissionExpireThread\");\n\n                boolean started = false;\n\n                permissionExpireThread = t;\n                try\n                {\n                    t.start();\n                    started = true;\n                }\n                finally\n                {\n                    if (!started && (permissionExpireThread == t))\n                        permissionExpireThread = null;\n                }\n            }\n        }\n    }\n\n    /**\n     * Runs in {@link #PermissionExpireThread} and expires the\n     * <tt>Permission</tt>s of this <tt>Allocation</tt> and removes them from\n     * {@link #permissions}.\n     */\n    private void runInAllocationPermissionExpireThread()\n    {\n        try\n        {\n            long idleStartTime = -1;\n\n            do\n            {\n                synchronized (permissions)\n                {\n                    try\n                    {\n                        permissions.wait(Permission.MAX_LIFETIME);\n                    }\n                    catch (InterruptedException ie)\n                    {\n                    }\n\n                    /*\n                     * Is the current Thread still designated to expire the\n                     * Permissions of this Allocation?\n                     */\n                    if (Thread.currentThread() != permissionExpireThread)\n                        break;\n\n                    long now = System.currentTimeMillis();\n\n                    /*\n                     * Has the current Thread been idle long enough to merit\n                     * disposing of it?\n                     */\n                    if (permissions.isEmpty())\n                    {\n                        if (idleStartTime == -1)\n                            idleStartTime = now;\n                        else if (now - idleStartTime > 60 * 1000)\n                            break;\n                    }\n                    else\n                    {\n                        // Expire the Permissions of this Allocation.\n\n                        idleStartTime = -1;\n\n                        for (Iterator<Permission> i =\n                            permissions.values().iterator(); i.hasNext();)\n                        {\n                            Permission permission = i.next();\n\n                            if (permission == null)\n                            {\n                                i.remove();\n                            }\n                            else if (permission.isExpired(now))\n                            {\n                                logger.finer(\"Permission \" + permission\n                                    + \" expired\");\n                                i.remove();\n                                permission.expire();\n                            }\n                        }\n                    }\n                }\n            }\n            while (true);\n        }\n        finally\n        {\n            synchronized (permissions)\n            {\n                if (permissionExpireThread == Thread.currentThread())\n                    permissionExpireThread = null;\n                /*\n                 * If permissionExpireThread dies unexpectedly and yet it is\n                 * still necessary, resurrect it.\n                 */\n                if (permissionExpireThread == null)\n                    maybeStartPermissionExpireThread();\n            }\n        }\n    }\n\n    @Override\n    public int hashCode()\n    {\n        return this.fiveTuple.hashCode();\n    }\n\n    /**\n     * Since an Allocation is uniquely identified by its relay address or five\n     * tuple hence we only compare these members.\n     */\n    @Override\n    public boolean equals(Object o)\n    {\n        if (!(o instanceof Allocation))\n        {\n            return false;\n        }\n        Allocation allocation = (Allocation) o;\n        if (!this.fiveTuple.equals(allocation.fiveTuple))\n        {\n            return false;\n        }\n        if (!this.relayAddress.equals(allocation.relayAddress))\n        {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString()\n    {\n        return this.getRelayAddress().toString();\n    }\n \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ChannelBind.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.util.logging.Logger;\n\nimport org.ice4j.*;\n\n/**\n * This class is an implementation of ChannelBind in TURN protocol.\n * \n * @author Aakash Garg\n * \n */\npublic class ChannelBind\n{\n    /**\n     * Our class logger.\n     */\n    private static final Logger logger = Logger.getLogger(ChannelBind.class\n        .getName());\n    \n    /**\n     * The maximum lifetime allowed for a ChannelBind (10 min).\n     */\n    public static final long MAX_LIFETIME = 10 * 60 * 1000;\n\n    /**\n     * The IP address and port of the peer for which to create ChannelBind.\n     */\n    private final TransportAddress peerAddress;\n\n    /**\n     * Represents the channel no of the ChannelBind.\n     */\n    private final char channelNo;\n  \n    /**\n     * The time in milliseconds when the ChannelBinding will expire.\n     */\n    private long expirationTime = -1;\n\n    /**\n     * Determines whether or not the ChannelBinding has expired.\n     */\n    private boolean expired = true;\n\n    /**\n     * Creates a new ChannelBind object with MAX_LIFETIME as default lifetime\n     * value.\n     * \n     * @param peerAddress contains the peer IP address with port no and\n     *            transport protocol to be assigned.\n     * @param channelNo the channelNo of ChannelBind.\n     */\n    public ChannelBind( TransportAddress peerAddress, \n                        char channelNo)\n    {\n        this(peerAddress, channelNo, ChannelBind.MAX_LIFETIME);\n    }\n\n    /**\n     * Creates a new ChannelBind object with given lifetime value.\n     * \n     * @param peerAddress contains the peer IP address and transport protocol to\n     *            be assigned. The port value is ignored.\n     * @param channelNo the channelNo of the ChannelBind request.\n     * @param lifetime the lifetime of ChannelBind.\n     */\n    public ChannelBind( TransportAddress peerAddress, \n                        char channelNo,\n                        long lifetime)\n    {\n        this.peerAddress = peerAddress;\n        if (channelNo < 0x4000)\n            throw new IllegalArgumentException(\"Illegal value of channel no\");\n        this.channelNo = channelNo;\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * Creates a new ChannelBind object with given lifetime value and UDP as\n     * default protocol.\n     * \n     * @param peerAddress contains the peer IP address and port no in String\n     *            format.\n     * @param channelNo the channelNo of the ChannelBind.\n     * @param lifetime the lifetime of ChannelBind.\n     */\n    public ChannelBind( String peerAddress, \n                        char channelNo, \n                        long lifetime)\n    {\n        this(new TransportAddress(peerAddress, 0, Transport.UDP), \n             channelNo,\n             lifetime);\n    }\n\n    /**\n     * @return the peerAddress as a String.\n     */\n    public String getPeerAddressString()\n    {\n        return this.getPeerAddress().getHostAddress();\n    }\n    \n    /**\n     * Returns the Peer Address associated with this ChannelBind.\n     */\n    public TransportAddress getPeerAddress()\n    {\n        return peerAddress;\n    }\n    \n    /**\n     * returns the channelNo associated with this ChannelBind.\n     */\n    public char getChannelNo()\n    {\n        return channelNo;\n    }\n \n    /**\n     * Returns the lifetime associated with this ChannelBind.\n     * If the ChannelBind is expired it returns 0. \n     */\n    public long getLifetime()\n    {\n        if(!isExpired())\n        {\n            return (this.expirationTime-System.currentTimeMillis());\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    \n    /**\n     *  Sets the time to expire in milliseconds for this ChannelBind.\n     *  Max lifetime can be ChannelBind.MAX_LIFEIME.\n     *  \n     *  @param lifetime the lifetime for this ChannelBind.\n     */\n    public void setLifetime(long lifetime)\n    {\n        synchronized(this)\n        {\n            this.expirationTime = System.currentTimeMillis()\n                + Math.min(lifetime*1000, ChannelBind.MAX_LIFETIME);\n        }\n    }\n\n    /**\n     * Refreshes the ChannelBind with the MAX_LIFETIME value.\n     */\n    public void refresh()\n    {\n        this.setLifetime(ChannelBind.MAX_LIFETIME);\n    }\n    \n    /**\n     * refreshes the ChannelBind with given lifetime value.\n     * @param lifetime the required lifetime of ChannelBind.\n     */\n    public void refresh(int lifetime)\n    {\n        this.setLifetime(lifetime);\n    }\n    \n    /**\n     * Start the ChannelBind. This launches the countdown to the moment the\n     * ChannelBind would expire.\n     */\n    public synchronized void start()\n    {\n        synchronized(this)\n        {\n            if (expirationTime == -1)\n            {\n                expired = false;\n                expirationTime = MAX_LIFETIME + System.currentTimeMillis();\n            }\n            else\n            {\n                throw new IllegalStateException(\n                        \"ChannelBind has already been started!\");\n            }\n        }\n    }\n    \n    /**\n     * Determines whether this <tt>ChannelBind</tt> is expired now.\n     *\n     * @return <tt>true</tt> if this <tt>ChannelBind</tT> is expired\n     * now; otherwise, <tt>false</tt>\n     */\n    public boolean isExpired()\n    {\n        return isExpired(System.currentTimeMillis());\n    }\n    \n    /**\n     * Expires the ChannelBind. Once this method is called the ChannelBind is\n     * considered terminated.\n     */\n    public synchronized void expire()\n    {\n        expired = true;\n        /*\n         * Allocation has a background Thread running with the purpose of\n         * removing expired ChannelBinds.\n         */\n    }\n    \n    /**\n     * Determines whether this <tt>ChannelBind</tt> will be expired at\n     * a specific point in time.\n     *\n     * @param now the time in milliseconds at which the <tt>expired</tt> state\n     * of this <tt>ChannelBind</tt> is to be returned\n     * @return <tt>true</tt> if this <tt>ChannelBind</tt> will be\n     * expired at the specified point in time; otherwise, <tt>false</tt>\n     */\n    public synchronized boolean isExpired(long now)\n    {\n        if (expirationTime == -1)\n            return false;\n        else if (expirationTime < now)\n            return true;\n        else\n            return expired;\n    }\n    \n    \n    @Override\n    public int hashCode()\n    {\n        return channelNo + peerAddress.hashCode();\n    }\n\n    @Override\n    public boolean equals(Object o)\n    {\n        if(!(o instanceof ChannelBind))\n        {\n            return false;\n        }\n        ChannelBind c = (ChannelBind) o;\n        if(c.getChannelNo() == this.channelNo\n                && c.getPeerAddress().equals(this.peerAddress))\n        {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"ChannelBind [\"\n            + (peerAddress != null ? \"peerAddress=\" + peerAddress + \", \" : \"\")\n            + \"channelNo=\" + (int)channelNo + \"]\";\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/FiveTuple.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.util.logging.*;\nimport org.ice4j.*;\n\n/**\n * The class would represent the FiveTuple object of TURN protocol. The hashCode\n * function should be unique if possible since it will be used to uniquely find\n * the allocation object.\n * \n * @author Aakash Garg\n */\npublic class FiveTuple\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>FiveTuple</tt> class and its\n     * instances for logging output.\n     */\n    private static final Logger logger = Logger.getLogger(FiveTuple.class\n        .getName());\n\n    /**\n     * Represents the Client's Transport Address.\n     */\n    protected TransportAddress clientTransportAddress;\n\n    /**\n     * Represents the Server's Transport Address.\n     */\n    protected TransportAddress serverTransportAddress;\n\n    /**\n     * Represents the Transport Protocol.\n     */\n    protected Transport transport = Transport.UDP;\n\n    /**\n     * Creates a new Five tuple Object with given arguments.\n     * \n     * @param clientTransportAddress The client's Address to be set\n     * @param serverTransportAddress The server's Address to be set\n     * @param transport The transport protocol of the client server connection.\n     */\n    public FiveTuple(TransportAddress clientAddress,\n        TransportAddress serverAddress, Transport transport)\n    {\n        this.clientTransportAddress = clientAddress;\n        this.serverTransportAddress = serverAddress;\n        this.transport = transport;\n    }\n\n    /**\n     * @return the clientTransportAddress or null if the the Client's Address\n     *         has not been set.\n     */\n    public TransportAddress getClientTransportAddress()\n    {\n        return clientTransportAddress;\n    }\n\n    /**\n     * @return client's port number as +ve int value or -1 if the the Client's\n     *         Address has not been set.\n     */\n    public int getClientPortNo()\n    {\n        if (this.clientTransportAddress != null)\n        {\n            return this.clientTransportAddress.getPort();\n        }\n        return -1;\n    }\n\n    /**\n     * @return client Host Address in String or null if the the Client's Address\n     *         has not been set.\n     */\n    public String getClientHostAddress()\n    {\n        if (this.clientTransportAddress != null)\n        {\n            return this.clientTransportAddress.getHostAddress();\n        }\n        else\n        {\n            return null;\n        }\n    }\n\n    /**\n     * @param clientTransportAddress The client's IP Address to be set.\n     */\n    public void setClientTransportAddress(TransportAddress clientAddress)\n    {\n        this.clientTransportAddress = clientAddress;\n    }\n\n    /**\n     * @return the serverTransportAddress or null if the the Server's Address\n     *         has not been set.\n     */\n    public TransportAddress getServerTransportAddress()\n    {\n        return serverTransportAddress;\n    }\n\n    /**\n     * @return server's port number as +ve int value or -1 if the the Server's\n     *         Address has not been set.\n     */\n    public int getServerPortNo()\n    {\n        if (this.serverTransportAddress != null)\n        {\n            return this.serverTransportAddress.getPort();\n        }\n        else\n        {\n            return -1;\n        }\n    }\n\n    /**\n     * @return server Host Address in String or null if the the Server's Address\n     *         has not been set.\n     */\n    public String getServerHostAddress()\n    {\n        if (this.serverTransportAddress != null)\n        {\n            return this.serverTransportAddress.getHostAddress();\n        }\n        else\n        {\n            return null;\n        }\n    }\n\n    /**\n     * @param serverTransportAddress The Server's Address to be set.\n     */\n    public void setServerTransportAddress(TransportAddress serverAddress)\n    {\n        this.serverTransportAddress = serverAddress;\n    }\n\n    /**\n     * @return the transport protocol used for client server connection.\n     */\n    public Transport getTransport()\n    {\n        return transport;\n    }\n\n    /**\n     * @param transport the transport to set.\n     */\n    public void setTransport(Transport transport)\n    {\n        this.transport = transport;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#hashCode()\n     */\n    @Override\n    public int hashCode()\n    {\n        final int prime = 31;\n        int result = 1;\n        result =\n            prime\n                * result\n                + ((clientTransportAddress == null) ? 0\n                    : clientTransportAddress.hashCode());\n        result =\n            prime\n                * result\n                + ((serverTransportAddress == null) ? 0\n                    : serverTransportAddress.hashCode());\n        result =\n            prime * result + ((transport == null) ? 0 : transport.hashCode());\n        return result;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#equals(java.lang.Object)\n     */\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#equals(java.lang.Object)\n     */\n    @Override\n    public boolean equals(Object obj)\n    {\n        if (this == obj)\n        {\n            return true;\n        }\n        if (obj == null)\n        {\n            return false;\n        }\n        if (!(obj instanceof FiveTuple))\n        {\n            return false;\n        }\n        FiveTuple other = (FiveTuple) obj;\n        if (clientTransportAddress == null)\n        {\n            if (other.clientTransportAddress != null)\n            {\n                return false;\n            }\n        }\n        else if (!clientTransportAddress.equals(other.clientTransportAddress))\n        {\n            return false;\n        }\n        if (serverTransportAddress == null)\n        {\n            if (other.serverTransportAddress != null)\n            {\n                return false;\n            }\n        }\n        else if (!serverTransportAddress.equals(other.serverTransportAddress))\n        {\n            return false;\n        }\n        if (transport != other.transport)\n        {\n            return false;\n        }\n        return true;\n    }\n\n    /*\n     * (non-Javadoc)\n     * \n     * @see java.lang.Object#toString()\n     */\n    @Override\n    public String toString()\n    {\n        return \"FiveTuple [\"\n            + (getClientTransportAddress() != null ? \"getClientAddress()=\"\n                + getClientTransportAddress() + \", \" : \"\")\n            + (getServerTransportAddress() != null ? \"getServerAddress()=\"\n                + getServerTransportAddress() + \", \" : \"\")\n            + (getTransport() != null ? \"getTransport()=\" + getTransport()\n                + \", \" : \"\") + \"hashCode()=\" + hashCode() + \"]\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/Permission.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport org.ice4j.*;\n\n/**\n * This class is an implementation of Permissions in TURN protocol.\n * \n * @author Aakash Garg\n * \n */\npublic class Permission\n{\n    /**\n     * The maximum lifetime allowed for a Permission.\n     */\n    public static final long MAX_LIFETIME = 300 * 1000;\n\n    /**\n     * The IP address of the peer for which to create Permission.\n     */\n    private TransportAddress ipAddress;\n /**\n     * The time in milliseconds when the Permission will expire.\n     */\n    private long expirationTime = -1;\n\n    /**\n     * Determines whether or not the Permission has expired.\n     */\n    private boolean expired = false;\n\n    /**\n     * @param ipAddress contains the peer IP address and transport protocol to\n     *            be assigned. The port value is ignored.\n     */\n    public Permission(TransportAddress ipAddress)\n    {\n        this.setIpAddress(ipAddress);\n        this.setLifetime(Permission.MAX_LIFETIME);\n    }\n    \n    /**\n     * @param ipAddress contains the peer IP address and transport protocol to\n     *            be assigned. The port value is ignored.\n     * @param lifetime the lifetime of permission.\n     */\n    public Permission(TransportAddress ipAddress, long lifetime)\n    {\n        this.setIpAddress(ipAddress);\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * @param ipAddress contains the peer IP address in String format.\n     * @param lifetime the lifetime of permission.\n     */\n    public Permission(String ipAddress, long lifetime)\n    {\n        this.setIpAddress(ipAddress);\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * @return the ipAddress of the Permission as a TransportAddress.\n     */\n    public TransportAddress getIpAddress()\n    {\n        return ipAddress;\n    }\n\n    /**\n     * @return the ipAddress as a String.\n     */\n    public String getIpAddressString()\n    {\n        return this.getIpAddress().getHostAddress();\n    }\n\n    /**\n     * @param ipAddress the ipAddress of the peer for which to create\n     *            Permission.\n     */\n    public void setIpAddress(TransportAddress ipAddress)\n    {\n        this.ipAddress =\n            new TransportAddress(ipAddress.getHostAddress(), 0,\n                ipAddress.getTransport());\n    }\n\n    /**\n     * @param ipAddress the ipAddress as String of the peer for which to create\n     *            Permission.\n     */\n    public void setIpAddress(String ipAddress)\n    {\n        this.ipAddress = new TransportAddress(ipAddress, 0, Transport.UDP);\n    }\n\n    /**\n     * Returns the lifetime associated with this Permission.\n     * If the Permission is expired it returns 0. \n     */\n    public long getLifetime()\n    {\n        if(!isExpired())\n        {\n            return (this.expirationTime-System.currentTimeMillis());\n        }\n        else\n        {\n            return 0;\n        }\n    }\n    \n    /**\n     *  Sets the time to expire in milli-seconds for this Permission.\n     *  Max lifetime can be Permission.MAX_LIFEIME.\n     *  \n     *  @param lifetime the lifetime for this Permission.\n     */\n    public void setLifetime(long lifetime)\n    {\n        synchronized(this)\n        {\n            this.expirationTime = System.currentTimeMillis()\n                + Math.min(lifetime*1000, Permission.MAX_LIFETIME);\n        }\n    }\n    \n    /**\n     * Refreshes the permission with the MAX_LIFETIME value.\n     */\n    public void refresh()\n    {\n        this.setLifetime(Permission.MAX_LIFETIME);\n    }\n    \n    /**\n     * refreshes the permission with given lifetime value.\n     * @param lifetime the required lifetime of permission.\n     */\n    public void refresh(int lifetime)\n    {\n        this.setLifetime(lifetime);\n    }\n\n    /**\n     * Start the Permission. This launches the countdown to the moment the\n     * Permission would expire.\n     */\n    public synchronized void start()\n    {\n        synchronized(this)\n        {\n            if (expirationTime == -1)\n            {\n                expired = false;\n                expirationTime = MAX_LIFETIME + System.currentTimeMillis();\n            }\n            else\n            {\n                throw new IllegalStateException(\n                        \"Permission has already been started!\");\n            }\n        }\n    }\n    \n    /**\n     * Determines whether this <tt>Permission</tt> is expired now.\n     *\n     * @return <tt>true</tt> if this <tt>Permission</tT> is expired\n     * now; otherwise, <tt>false</tt>\n     */\n    public boolean isExpired()\n    {\n        return isExpired(System.currentTimeMillis());\n    }\n    \n    /**\n     * Expires the Permission. Once this method is called the Permission is\n     * considered terminated.\n     */\n    public synchronized void expire()\n    {\n        expired = true;\n        /*\n         * TurnStack has a background Thread running with the purpose of\n         * removing expired Permissions.\n         */\n    }\n    \n    /**\n     * Determines whether this <tt>Permission</tt> will be expired at\n     * a specific point in time.\n     *\n     * @param now the time in milliseconds at which the <tt>expired</tt> state\n     * of this <tt>Permission</tt> is to be returned\n     * @return <tt>true</tt> if this <tt>Permission</tt> will be\n     * expired at the specified point in time; otherwise, <tt>false</tt>\n     */\n    public synchronized boolean isExpired(long now)\n    {\n        if (expirationTime == -1)\n            return false;\n        else if (expirationTime < now)\n            return true;\n        else\n            return expired;\n    }\n    /*\n     * The permission is uniquely identified by its IP address, so hashCode is\n     * calculated on the IP address only.\n     */\n    @Override\n    public int hashCode()\n    {\n        return ipAddress.getHostAddress().hashCode();\n    }\n\n    /*\n     * Two Permissions are equal if their associated IP address, lifetime and\n     * transport protocol are same.\n     */\n    @Override\n    public boolean equals(Object obj)\n    {\n        if (!(obj instanceof Permission))\n        {\n            return false;\n        }\n        Permission other = (Permission) obj;\n        if (ipAddress == null)\n        {\n            if (other.ipAddress != null)\n            {\n                return false;\n            }\n        }\n        else if (ipAddress.getHostAddress().compareTo(\n            other.ipAddress.getHostAddress()) != 0)\n        {\n            return false;\n        }\n        if (expirationTime != other.expirationTime)\n        {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString()\n    {\n        return \"Permission [\"\n            + (ipAddress != null ? \"ipAddress=\" + ipAddress : \"\") + \"]\";\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ServerChannelDataEventHandler.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.util.Arrays;\nimport java.util.logging.*  ;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * Class to handle incoming ChannelData messages coming from Client to Server.\n * It first finds if there is a ChannelBind installed for the peer. \n * If yes it then sends the UDP message to peer.\n * If no it then silently ignores the message.\n * \n * @author Aakash Garg\n */\npublic class ServerChannelDataEventHandler implements\n\tChannelDataEventHandler {\n    \n    /**\n     * The <tt>Logger</tt> used by the\n     * <tt>ServerChannelDataEventHandler</tt> class and its instances for\n     * logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ServerChannelDataEventHandler.class.getName());\n\n    /**\n     * The turnStack to call.\n     */\n    private TurnStack turnStack;\n\n    /**\n     * Default Constructor.\n     */\n    public ServerChannelDataEventHandler()\n    {\n    }\n    \n    /**\n     * Parametrized constructor.\n     * @param turnStack the turnStack to set for this class.\n     */\n    public ServerChannelDataEventHandler(StunStack turnStack) \n    {\n\tif (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    /**\n     * Sets the TurnStack for this class.\n     * @param turnStack the turnStack to set for this class.\n     */\n    public void setTurnStack(TurnStack turnStack)\n    {\n\tthis.turnStack = turnStack;\n    }\n    \n    /**\n     * Handles the ChannelDataMessageEvent.\n     * @param evt the ChannelDataMessageEvent to handle/process.\n     */\n    @Override\n    public void handleMessageEvent(ChannelDataMessageEvent evt) \n    {\n        if(!logger.isLoggable(Level.FINER)){\n            logger.setLevel(Level.FINER);\n        }\n\tChannelData channelData = evt.getChannelDataMessage();\n\tchar channelNo = channelData.getChannelNumber();\n\tbyte[] data = channelData.getData();\n\tlogger.finer(\"Received a ChannelData message for \" + (int)channelNo\n\t\t+ \" , message : \" + Arrays.toString(data));\n\t\n\tTransportAddress clientAddress = evt.getRemoteAddress();\n        TransportAddress serverAddress = evt.getLocalAddress();\n        Transport transport = Transport.UDP;\n        FiveTuple fiveTuple =\n            new FiveTuple(clientAddress, serverAddress, transport);\n        \n        Allocation allocation \n            = this.turnStack.getServerAllocation(fiveTuple);\n        \n        if(allocation==null)\n        {\n            logger.finer(\"allocation not found.\");\n        }\n        else if(!allocation.containsChannel(channelNo))\n        {\n\t    logger.finer(\"ChannelNo \" + (int) channelNo\n\t\t    + \" not found in Allocation!\");\n            return;\n        }\n        TransportAddress destAddr = allocation.getPeerAddr(channelNo);\n        if(destAddr != null)\n        {\n\t    RawMessage message = RawMessage.build(data, data.length, destAddr,\n\t\t    allocation.getClientAddress());\n\t    try {\n\t\tlogger.finer(\"Dispatching a UDP message to \" + destAddr\n\t\t\t+ \", data: \" + Arrays.toString(message.getBytes()));\n\t\tthis.turnStack.sendUdpMessage(message, destAddr,\n\t\t    allocation.getRelayAddress());\n\t    } catch (StunException e) {\n\t\tlogger.finer(e.getMessage());\n\t    }\n        }\n        else\n        {\n\t    logger.finer(\"Peer address not found for channel \"\n\t\t    + (int) channelNo);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ServerPeerUdpEventHandler.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.util.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\n/**\n * Class to handle UDP messages coming from Peer. The class first checks if\n * there is a non-expired ChannelBind for the peer if yes it then sends a\n * ChannelData message to Client. If no it then finds if there is a non-expired\n * permission if yes then it sends a DataIndicatio to Client. All the mesages\n * sent to client here are from the address on which the allocation request was\n * received or the serverAddress of fiveTuple of corresponding Allocation.\n * \n * @author Aakash Garg\n */\npublic class ServerPeerUdpEventHandler\n    implements PeerUdpMessageEventHandler\n{\n    /**\n     * The <tt>Logger</tt> used by the <tt>PeerUdpMessageEventHandler</tt> class\n     * and its instances for logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ServerPeerUdpEventHandler.class.getName());\n\n    /**\n     * The turnStack to call.\n     */\n    private TurnStack turnStack;\n\n    /**\n     * Default constructor.\n     */\n    public ServerPeerUdpEventHandler()\n    {\n    }\n\n    /**\n     * Parametrized constructor.\n     * \n     * @param turnStack the turnStack to set for this class.\n     */\n    public ServerPeerUdpEventHandler(StunStack turnStack)\n    {\n        if (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    public void setTurnStack(TurnStack turnStack)\n    {\n        this.turnStack = turnStack;\n    }\n\n    /**\n     * Handles the PeerUdpMessageEvent.\n     * \n     * @param evt the PeerUdpMessageEvent to handle/process.\n     */\n    @Override\n    public void handleMessageEvent(PeerUdpMessageEvent evt)\n    {\n        if (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n            logger.finer(\"Received Peer UdP message message \" + evt);\n        }\n\n        byte[] data = evt.getBytes();\n        TransportAddress localAddress = evt.getLocalAddress();\n        TransportAddress remoteAddress = evt.getRemoteAddress();\n        logger.finest(\"Received a UDP message on: \" + localAddress + \", data: \"\n            + byteArrayToHex(data));\n        Allocation allocation =\n            this.turnStack.getServerAllocation(localAddress);\n        if (remoteAddress.getTransport() == Transport.TCP)\n        {\n            FiveTuple fiveTuple =\n                new FiveTuple(remoteAddress, localAddress, Transport.TCP);\n            logger.finest(\"Send message request from \"+fiveTuple);\n            if (allocation == null) // came from client\n            {\n                // get client allocation\n                logger.finest(\"Message came from TCP Client\");\n                int connectionId =\n                    this.turnStack.getConnectionIdForDataConn(fiveTuple);\n                logger.finest(\"Connection Id extracted for \"+fiveTuple+\" is \"+connectionId);\n                allocation = this.turnStack.getAllocationFromConnectionId(connectionId);\n                logger.finest(\"Allocation extracted is \"+allocation+\" for client-\"+fiveTuple);\n                FiveTuple peerTuple =\n                    allocation.getPeerTCPConnection(connectionId);\n                TransportAddress peerAddress =\n                    peerTuple.getClientTransportAddress();\n                TransportAddress relayAddress =\n                    peerTuple.getServerTransportAddress();\n                RawMessage rawMessage =\n                    RawMessage.build(data, data.length, peerAddress,\n                    relayAddress);\n                try\n                {\n                    logger.finest(\"Relaying data to peer-\" + peerAddress\n                        + \" from \" + remoteAddress+\" data-\");\n                    this.turnStack.sendUdpMessage(\n                        rawMessage, peerAddress, relayAddress);\n                }\n                catch (StunException e)\n                {\n                    System.err.println(\"Unable to relay message to peer-\"\n                        + peerAddress + \" from client-\" + remoteAddress\n                        + \" message-\" + Arrays.toString(data));\n                }\n\n            }\n            else\n            {\n                // else came from peer\n                logger.finest(\"Message came from TCP peer.\");\n                int connectionId =\n                    this.turnStack.getConnectionIdForPeer(fiveTuple);\n                if (!allocation.isPermitted(remoteAddress))\n                {\n                    logger.finest(\"No permission installed for peer-\"+remoteAddress);\n                    return;\n                }\n                else\n                {\n                    TransportAddress dataConn = allocation.getDataConnection(\n                        connectionId).getClientTransportAddress();\n                    if (dataConn != null)\n                    {\n                        RawMessage rawMessage =\n                            RawMessage.build(data, data.length, dataConn,\n                            allocation.getServerAddress());\n                        try\n                        {\n                            logger.finest(\"Relaying data to client-\" + dataConn\n                                + \" from peer-\" + remoteAddress);\n                            this.turnStack.sendUdpMessage(\n                                rawMessage, dataConn,\n                                allocation.getServerAddress());\n                        }\n                        catch (StunException e)\n                        {\n                            System.err\n                                .println(\"Unable to relay message to client-\"\n                                    + dataConn + \" from peer-\" + remoteAddress\n                                    + \" message-\" + Arrays.toString(data));\n                        }\n                    }else{\n                        logger.finest(\"No data connection found for peer-\"\n                            + remoteAddress);\n                    }\n                }\n            }\n        }\n        else if (allocation != null\n            && allocation.getChannel(remoteAddress) != 0x1000)\n        {\n            char channelNo = allocation.getChannel(remoteAddress);\n            ChannelData channelData = new ChannelData();\n            channelData.setChannelNumber(channelNo);\n            channelData.setData(data);\n            try\n            {\n                logger.finest(\"Sending a ChannelData message \" + channelData\n                    + \" from \" + allocation.getServerAddress() + \" to \"\n                    + allocation.getClientAddress());\n\n                this.turnStack.sendChannelData(\n                    channelData, allocation.getClientAddress(),\n                    allocation.getServerAddress());\n            }\n            catch (StunException ex)\n            {\n                logger.finer(ex.getMessage());\n            }\n        }\n        else if (allocation != null && allocation.isPermitted(remoteAddress))\n        {\n            TransactionID tranID = TransactionID.createNewTransactionID();\n            Indication dataInd = MessageFactory.createDataIndication(\n                remoteAddress, data, tranID.getBytes());\n            try\n            {\n                logger.finest(\"Sending a ChannelData message \" + dataInd\n                    + \" from \" + allocation.getServerAddress() + \" to \"\n                    + allocation.getClientAddress());\n\n                this.turnStack.sendIndication(\n                    dataInd, allocation.getClientAddress(),\n                    allocation.getServerAddress());\n            }\n            catch (StunException e)\n            {\n                logger.finer(e.getMessage());\n            }\n        }else{\n            logger\n                .finest(\"unable to find allocation and the message is not on TCP.\");\n        }\n    }\n    \n    private String byteArrayToHex(byte[] data){\n        String arrayToHex= \"\";\n        for(int i=0; i<data.length; i++){\n            arrayToHex += String.format(\"%02X, \", data[i]); \n        }\n        return arrayToHex;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnClientTransaction.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport org.ice4j.ResponseCollector;\nimport org.ice4j.StunMessageEvent;\nimport org.ice4j.TransportAddress;\nimport org.ice4j.message.Request;\nimport org.ice4j.stack.*;\n\n/**\n * {@inheritDoc}\n */\npublic class TurnClientTransaction\n    extends StunClientTransaction\n{\n\n    /**\n     * {@inheritDoc}\n     */\n    public TurnClientTransaction(   StunStack stackCallback, \n                                    Request request,\n                                    TransportAddress requestDestination, \n                                    TransportAddress localAddress,\n                                    ResponseCollector responseCollector, \n                                    TransactionID transactionID)\n    {\n        super(stackCallback, request, requestDestination, localAddress,\n            responseCollector, transactionID);\n    }\n\n    /**\n     * /** {@inheritDoc}\n     */\n    public TurnClientTransaction(   StunStack stackCallback, \n                                    Request request,\n                                    TransportAddress requestDestination, \n                                    TransportAddress localAddress,\n                                    ResponseCollector responseCollector)\n    {\n        super(stackCallback, request, requestDestination, localAddress,\n            responseCollector);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public synchronized void handleResponse(StunMessageEvent evt)\n    {\n        super.handleResponse(evt);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnServer.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.io.*;\nimport java.net.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.socket.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.listeners.*;\n\n/**\n * The class to run a Turn server.\n * \n * @author Aakash Garg\n */\npublic class TurnServer\n{\n    private static Logger logger = Logger.getLogger(TurnServer.class.getName());\n\n    private TransportAddress localAddress = null;\n\n    // requested maximum length of the queue of incoming connections\n    private int backlog = 50;\n\n    private boolean started = false;\n\n    private TurnStack turnStack = null;\n\n    private IceUdpSocketWrapper turnUdpSocket;\n\n    private final ServerPeerUdpEventHandler peerUdpHandler;\n\n    private final ServerChannelDataEventHandler channelDataHandler;\n\n    private IceSocketWrapper turnTcpServerSocket;\n\n    public TurnServer(TransportAddress localUDPAddress)\n    {\n        this.localAddress = localUDPAddress;\n        this.peerUdpHandler = new ServerPeerUdpEventHandler();\n        this.channelDataHandler = new ServerChannelDataEventHandler();\n\n        turnStack = new TurnStack(this.peerUdpHandler, this.channelDataHandler);\n        System.out.println(\"Setting turnstack.\");\n        this.peerUdpHandler.setTurnStack(turnStack);\n        this.channelDataHandler.setTurnStack(turnStack);\n\n        logger.info(\"Server initialized Waiting to be started\");\n    }\n\n    /**\n     * @param args\n     */\n    public static void main(String[] args) throws Exception\n    {\n        TransportAddress localAddress = null;\n        if (args.length == 2)\n        {\n            localAddress =\n                new TransportAddress(args[0], Integer.valueOf(args[1]),\n                    Transport.UDP);\n        }\n        else\n        {\n            localAddress =\n                new TransportAddress(InetAddress.getLocalHost(), 3478,\n                    Transport.UDP);\n        }\n        TurnServer server = new TurnServer(localAddress);\n        server.start();\n        Thread.sleep(600 * 1000);\n        if (server.isStarted())\n        {\n            server.shutDown();\n        }\n    }\n\n    /**\n     * Function to start the server\n     * \n     * @throws IOException\n     * @throws TurnException\n     */\n    public void start() throws IOException, TurnException\n    {\n        if (localAddress == null)\n        {\n            throw new RuntimeException(\"Local address not initialized\");\n        }\n\n        AllocationRequestListener allocationRequestListner =\n            new AllocationRequestListener(turnStack);\n        ChannelBindRequestListener channelBindRequestListener =\n            new ChannelBindRequestListener(turnStack);\n        ConnectionBindRequestListener connectionBindRequestListener =\n            new ConnectionBindRequestListener(turnStack);\n        ConnectRequestListener connectRequestListener =\n            new ConnectRequestListener(turnStack);\n        CreatePermissionRequestListener createPermissionRequestListener =\n            new CreatePermissionRequestListener(turnStack);\n        RefreshRequestListener refreshRequestListener =\n            new RefreshRequestListener(turnStack);\n        BindingRequestListener bindingRequestListener =\n            new BindingRequestListener(turnStack);\n\n        SendIndicationListener sendIndListener =\n            new SendIndicationListener(turnStack);\n        sendIndListener.setLocalAddress(localAddress);\n\n        allocationRequestListner.start();\n        channelBindRequestListener.start();\n        connectionBindRequestListener.start();\n        connectRequestListener.start();\n        createPermissionRequestListener.start();\n        refreshRequestListener.start();\n        bindingRequestListener.start();\n\n        sendIndListener.start();\n\n        System.out.println(\"Local address - \" + localAddress.getHostAddress()\n            + \":\" + localAddress.getPort());\n        // instance a server socket for TCP\n        ServerSocket tcpServerSocket =\n            new ServerSocket(localAddress.getPort(), backlog,\n            localAddress.getAddress());\n        // set reuse to allow binding the socket to the same address\n        tcpServerSocket.setReuseAddress(true);\n        System.out.println(\"Adding a TCP server socket - \"\n            + tcpServerSocket.getLocalSocketAddress());\n        // create ICE socket wrapper for TCP\n        turnTcpServerSocket = new IceTcpServerSocketWrapper(tcpServerSocket,\n            turnStack.getComponent());\n        // instance a datagram socket for UDP\n        SafeCloseDatagramSocket udpServerSocket =\n            new SafeCloseDatagramSocket(localAddress.getPort(),\n            localAddress.getAddress());\n        // set reuse to allow binding the datagram socket to the same address\n        udpServerSocket.setReuseAddress(true);\n        System.out.println(\"Adding a UDP server socket - \"\n            + udpServerSocket.getLocalSocketAddress());\n        // create ICE socket wrapper for UDP\n        turnUdpSocket = new IceUdpSocketWrapper(udpServerSocket);\n        // add the TCP socket to the stack\n        turnStack.addSocket(turnTcpServerSocket);\n        // add the UDP socket to the stack\n        turnStack.addSocket(turnUdpSocket);\n        started = true;\n        logger.info(\"Server started, listening on \" + localAddress.getAddress()\n            + \":\" + localAddress.getPort());\n\n    }\n\n    /**\n     * function to stop the server and free resources allocated by it.\n     */\n    public void shutDown()\n    {\n        logger.info(\"Stopping server at \" + localAddress.getAddress() + \":\"\n            + localAddress.getPort());\n        turnStack.removeSocket(localAddress);\n        turnStack = null;\n        turnUdpSocket.close();\n        turnUdpSocket = null;\n        this.turnTcpServerSocket.close();\n        this.turnTcpServerSocket = null;\n        \n        localAddress = null;\n        this.started = false;\n        logger.info(\"Server stopped\");\n    }\n\n    public boolean isStarted()\n    {\n        return started;\n    }\n\n    /**\n     * Sets the incoming connection backlog.\n     *\n     * @param backlog\n     */\n    public void setBacklog(int backlog)\n    {\n        this.backlog = backlog;\n    }\n\n    @Override\n    public void finalize() throws Throwable\n    {\n        // to free resources by default if shutdown is not invoked before the\n        // object is destroyed\n        shutDown();\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnServerTransaction.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.io.IOException;\n\nimport org.ice4j.StunException;\nimport org.ice4j.TransportAddress;\nimport org.ice4j.message.Response;\nimport org.ice4j.stack.*;\n\n/**\n * The class represents the TURN server Transaction in turnserver.\n * It is just an inheritance of StunServerTransaction.\n * \n * @author Aakash Garg\n *\n */\npublic class TurnServerTransaction\n    extends StunServerTransaction\n{\n\n    /**\n     * {@inheritDoc}\n     */\n    public TurnServerTransaction(   StunStack stackCallback, \n                                    TransactionID tranID,\n                                    TransportAddress localListeningAddress, \n                                    TransportAddress requestSource)\n    {\n        super(stackCallback, tranID, localListeningAddress, requestSource);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected void retransmitResponse()\n        throws StunException,\n        IOException,\n        IllegalArgumentException\n    {\n        super.retransmitResponse();\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    protected Response getResponse()\n    {\n        return super.getResponse();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnStack.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport java.io.*;\nimport java.net.*;\nimport java.util.*;\nimport java.util.logging.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.ice.*;\nimport org.ice4j.message.*;\nimport org.ice4j.security.*;\nimport org.ice4j.socket.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.listeners.*;\nimport org.jitsi.turnserver.socket.*;\n\n/**\n * The entry point to the TurnServer stack. The class is used to start, stop and\n * configure the stack.\n * \n * @author Aakash Garg\n */\npublic class TurnStack\n    extends StunStack\n{\n\n    /**\n     * The <tt>Logger</tt> used by the <tt>turnStack</tt> class and its\n     * instances for logging output.\n     */\n    private static final Logger logger \n        = Logger.getLogger(TurnStack.class.getName());\n\n    /**\n     * The maximum no of Allocations per TurnStack.\n     */\n    public static final int MAX_ALLOCATIONS = 500;\n    \n    /**\n     * To track the portNo used.\n     */\n//    private static int nextPortNo = 49152;\n    private static int nextPortNo = 15000;\n    \n    /**\n     * Represents the Allocations stored for Server Side.\n     */\n    private final HashMap<FiveTuple,Allocation> serverAllocations\n        = new HashMap<FiveTuple,Allocation>();\n\n    /**\n     * Contains the mapping of relayAddress to Allocation.\n     */\n    private final HashMap<TransportAddress,Allocation> serverRelayAllocationMap\n        = new HashMap<TransportAddress,Allocation>();\n    \n    /**\n     * RelayAddress reserved by server.\n     */\n    private final HashSet<TransportAddress> reservedAddress\n        = new HashSet<TransportAddress>();\n    \n    /**\n     * Represents the Allocations stored for Client Side.\n     */\n    private final HashMap<FiveTuple,Allocation> clientAllocations\n        = new HashMap<FiveTuple,Allocation>();\n\n    /**\n     * Maps one-to-one from Data Connection to Connection Id.\n     */\n    private final HashMap<FiveTuple, Integer> dataConnToConnIdMap =\n        new HashMap<FiveTuple, Integer>();\n\n    /**\n     * Maps one-to-one from Peer TCP Connection to Connection Id.\n     */\n    private final HashMap<FiveTuple, Integer> peerConnToConnIdMap =\n        new HashMap<FiveTuple, Integer>();\n\n    /**\n     * Maps many-to-one from Connection Id to Allocation for where\n     * ConnectionBind Request has been received for Connection ID .\n     */\n    private final HashMap<Integer, Allocation> connIdToAllocMap =\n        new HashMap<Integer, Allocation>();\n\n    /**\n     * Contains unAcknowledged Connection Id. Every element will expire after\n     * min of 30 sec.\n     */\n    private final HashSet<Integer> unAcknowledgedConnId =\n        new HashSet<Integer>();\n\n    /**\n     * The <tt>Thread</tt> which expires the <tt>TurnServerAllocation</tt>s of\n     * this <tt>TurnStack</tt> and removes them from {@link #serverAllocations}\n     * .\n     */\n    private Thread serverAllocationExpireThread;\n        \n    /**\n     * Indicates that if the don't fragment is support or not.\n     */\n    private static final boolean dontFragmentSupported = false;\n\n    /**\n     * Component variable.\n     */\n    private Component component;\n\n    /**\n     * Boolean to allow or disallow TCP messages. Default is allowed.\n     */\n    private boolean tcpAllowed = true;\n    \n    /**\n     * Boolean to allow or disallow UDP messages. Default is allowed.\n     */\n    private boolean udpAllowed = true;\n    \n    /**\n     * Default Constructor. Initializes the NetAccessManager and\n     */\n    public TurnStack()\n    {\n        super();\n        initCredentials();\n    }\n\n    /**\n     * Parameterized constructor for TurnStack.\n     * \n     * @param peerUdpMessageEventHandler\n     *            the PeerUdpMessageEventHandler for this turnStack.\n     * @param channelDataEventHandler\n     *            the ChannelDataEventHandler for this turnStack.\n     */\n    public TurnStack(PeerUdpMessageEventHandler peerUdpMessageEventHandler,\n\t        ChannelDataEventHandler channelDataEventHandler) {\n\tsuper(peerUdpMessageEventHandler,channelDataEventHandler);\n        initCredentials();\n    }\n\n    /**\n     * Called to notify this provider for an incoming message. method overridden\n     * to modify the logic of the Turn Stack.\n     * \n     * @param ev the event object that contains the new message.\n     */\n    @Override\n    public void handleMessageEvent(StunMessageEvent ev)\n    {\n        Message msg = ev.getMessage();\n        logger.finest(\"Received an Event.\"+ev.getTransactionID());\n        if (!TurnStack.isTurnMessage(msg))\n        {\n            logger.finest(\"Ignored a non-TURN message!\");\n            return;\n        }\n        else\n        {\n            removeUsernameIntegrityFromBinding(ev.getMessage());\n            super.handleMessageEvent(ev);\n            return;\n        }\n        \n/*      logger.setLevel(Level.FINEST);\n        if (logger.isLoggable(Level.FINEST))\n        {\n            logger.finest(\"Received a message on \" + ev.getLocalAddress()\n                + \" of type:\" + (int) msg.getMessageType());\n        }\n\n        // request\n        if (msg instanceof Request)\n        {\n            TransactionID serverTid = ev.getTransactionID();\n            logger.finer(\"parsing request : \"+serverTid);\n            TurnServerTransaction sTran =\n                (TurnServerTransaction) getServerTransaction(serverTid);\n\n            if (sTran != null)\n            {\n                // requests from this transaction have already been seen\n                // retransmit the response if there was any\n                logger.finest(\"found an existing transaction\");\n\n                try\n                {\n                    sTran.retransmitResponse();\n                    logger.finest(\"Response retransmitted\");\n                }\n                catch (Exception ex)\n                {\n                    // we couldn't really do anything here .. apart from logging\n                    logger.log(\n                        Level.WARNING, \"Failed to retransmit a Turn response\",\n                        ex);\n                }\n\n                if (!Boolean\n                    .getBoolean(StackProperties.PROPAGATE_RECEIVED_RETRANSMISSIONS))\n                {\n                    return;\n                }\n            }\n            else\n            {\n                logger.finest(\"existing transaction not found\");\n                sTran =\n                    new TurnServerTransaction(this, serverTid,\n                        ev.getLocalAddress(), ev.getRemoteAddress());\n\n                // if there is an OOM error here, it will lead to\n                // NetAccessManager.handleFatalError that will stop the\n                // MessageProcessor thread and restart it that will lead again\n                // to an OOM error and so on... So stop here right now\n                try\n                {\n                    sTran.start();\n                }\n                catch (OutOfMemoryError t)\n                {\n                    logger.info(\"Turn transaction thread start failed:\" + t);\n                    return;\n                }\n                startNewServerTransactionThread(\n                    serverTid, sTran);\n            }\n\n            // validate attributes that need validation.\n            try\n            {\n//                validateRequestAttributes(ev);\n            }\n            catch (Exception exc)\n            {\n                // validation failed. log get lost.\n                logger.log(\n                    Level.FINE, \"Failed to validate msg: \" + ev, exc);\n                return;\n            }\n\n            try\n            {\n                fireMessageEventFormEventDispatcher(ev);\n            }\n            catch (Throwable t)\n            {\n                Response error;\n\n                logger.log(\n                    Level.INFO, \"Received an invalid request.\", t);\n                Throwable cause = t.getCause();\n\n                if (((t instanceof StunException) && ((StunException) t)\n                    .getID() == StunException.TRANSACTION_ALREADY_ANSWERED)\n                    || ((cause instanceof StunException) && ((StunException) cause)\n                        .getID() == StunException.TRANSACTION_ALREADY_ANSWERED))\n                {\n                    // do not try to send an error response since we will\n                    // get another TRANSACTION_ALREADY_ANSWERED\n                    return;\n                }\n\n                if (t instanceof IllegalArgumentException)\n                {\n                    error = MessageFactory.createBindingErrorResponse(\n                        ErrorCodeAttribute.BAD_REQUEST, t.getMessage());\n                }\n                else\n                {\n                    error =\n                        MessageFactory.createBindingErrorResponse(\n                            ErrorCodeAttribute.SERVER_ERROR,\n                            \"Oops! Something went wrong on our side :(\");\n                }\n\n                try\n                {\n                    sendResponse(\n                        serverTid.getBytes(), error, ev.getLocalAddress(),\n                        ev.getRemoteAddress());\n                }\n                catch (Exception exc)\n                {\n                    logger.log(\n                        Level.FINE, \"Couldn't send a server error response\",\n                        exc);\n                }\n            }\n        }\n        // response\n        else if (msg instanceof Response)\n        {\n            logger.finer(\"Parsing response\");\n            TransactionID tid = ev.getTransactionID();\n            StunClientTransaction tran =\n                removeTransactionFromClientTransactions(tid);\n            if (tran != null)\n            {\n                tran.handleResponse(ev);\n            }\n            else\n            {\n                // do nothing - just drop the phantom response.\n                logger\n                    .fine(\"Dropped response - no matching client tran found for\"\n                        + \" tid \" + tid + \"\\n\");\n            }\n        }\n        // indication\n        else if (msg instanceof Indication)\n        {\n            logger.finer(\"Dispatching a Indication.\");\n            fireMessageEventFormEventDispatcher(ev);\n        }\n*/    }\n    \n    \n    /**\n     * Method to know if the Don't fragment is supported.\n     * \n     * @return true if supported else false.\n     */\n    public static boolean isDontfragmentsupported()\n    {\n        return dontFragmentSupported;\n    }\n    \n    /**\n     * Returns the Allocation with the specified <tt>fiveTuple</tt> or\n     * <tt>null</tt> if no such Allocation exists.\n     * \n     * @param fiveTuple the fiveTuple of the Allocation we are looking for.\n     * \n     * @return the {@link Allocation} we are looking for.\n     */\n    public Allocation getServerAllocation(FiveTuple fiveTuple)\n    {\n        Allocation allocation = null;\n\n        synchronized (this.serverAllocations)\n        {\n            allocation = this.serverAllocations.get(fiveTuple);\n        }\n        /*\n         * If a Allocation is expired, do not return it. It will be\n         * removed from serverAllocations soon.\n         */\n        if ((allocation != null) && allocation.isExpired())\n            allocation = null;\n        return allocation;\n    }\n    \n    /**\n     * Returns the Allocation with the specified <tt>fiveTuple</tt> or\n     * <tt>null</tt> if no such Allocation exists.\n     * \n     * @param fiveTuple the fiveTuple of the Allocation we are looking for.\n     * \n     * @return the {@link Allocation} we are looking for.\n     */\n\n    public Allocation getClientAllocation(FiveTuple fiveTuple)\n    {\n        Allocation allocation;\n\n        synchronized (clientAllocations)\n        {\n            allocation = clientAllocations.get(fiveTuple);\n        }\n        /*\n         * If a Allocation is expired, do not return it. It will be\n         * removed from serverAllocations soon.\n         */\n        if ((allocation != null) && allocation.isExpired())\n            allocation = null;\n        return allocation;\n    }\n    \n    /**\n     * Determines if more allocations can be added to this TurnStack.\n     * \n     * @return true if no of allocations are less than maximum allowed\n     *         allocations per TurnStack.\n     */\n    public boolean canHaveMoreAllocations()\n    {\n       return (this.serverAllocations.size() < MAX_ALLOCATIONS);\n    }\n    \n    /**\n     * Adds a new server allocation to this TurnStack.\n     * \n     * @param allocation the allocation to be added to this TurnStack.\n     */\n    public synchronized void addNewServerAllocation(Allocation allocation)\n    {\n        synchronized(this.serverAllocations)\n        {\n            this.serverAllocations.put(allocation.getFiveTuple(), allocation);\n            IceSocketWrapper sock;\n            if(true)\n            {   // check if meanwhile other thread has put the same allocation.\n                try\n                {\n\t\t    logger.finer(\"Adding a new Socket for : \"\n\t\t\t    + allocation.getRelayAddress());\n\t\t    if(allocation.getRelayAddress().getTransport()==Transport.UDP)\n\t\t    {\n                    sock = new IceUdpSocketWrapper(\n                                new SafeCloseDatagramSocket(\n                                    allocation.getRelayAddress()));\n\t\t    }\n\t\t    else\n\t\t    {\n                        IceTcpEventizedServerSockerWrapper mySock2 =\n                            new IceTcpEventizedServerSockerWrapper(\n                                new ServerSocket(allocation.getRelayAddress()\n                                    .getPort()), this.getComponent());\n                        PeerTcpConnectEventListner listener =\n                            new PeerTcpConnectEventListner(this);\n                        mySock2.setEventListener(listener);\n                        sock = mySock2;\n/*\n                        sock =\n                            new IceTcpServerSocketWrapper(new ServerSocket(allocation\n                                .getRelayAddress().getPort()),this.getComponent());\n*/\t\t    }\n            this.addSocket(sock);\n\t\t    logger.finer(\"Added a new Socket for : \"\n\t\t\t    + allocation.getRelayAddress());\n\t\t    try\n\t\t    {\n\t\t\tallocation.start();\n\t\t    }\n\t\t    catch(Exception e)\n\t\t    {\n\t\t    }\n                }\n                catch (SocketException e)\n                {\n                    logger.finer(\"Error obtained : \"+e.getMessage());\n                    logger.log(Level.FINEST, \n                            \"Error! Cannot add new socket from TurnStack at \"\n                                +\"addNewServerAllocation \");\n                    logger.log(Level.FINEST, e.getMessage());\n             //       allocation.expire();\n                }\n                catch (UnknownHostException e)\n                {\n                    System.err.println(\"Unable to add TCP relay Address for : \"\n                        + allocation.getRelayAddress());\n                }\n                catch (IOException e)\n                {\n                    e.printStackTrace();\n                }\n            }\n            this.serverRelayAllocationMap.put(\n                        allocation.getRelayAddress(), \n                        allocation);\n            maybeStartServerAllocationExpireThread();\n        }\n    }\n    \n    /**\n     * Gets the allocation corresponding to the relay address.\n     * @param relayAddress the relayAddress for which to find allocation.\n     * @return the Allocation corresponding to relayAddress.\n     */\n    public Allocation getServerAllocation(TransportAddress relayAddress)\n    {\n\treturn this.serverRelayAllocationMap.get(relayAddress);\n    }\n    \n    /**\n     * Function to check if given IP is allowed for peer address.s\n     * @param peerAddr\n     * @return\n     */\n    public static boolean isIPAllowed(TransportAddress peerAddr)\n    {\n        String ip = peerAddr.getHostAddress();\n        int portNo = peerAddr.getPort();\n        //TODO : logic for validating the invalid IP address.\n        return true;\n    }\n    \n    /**\n     * Reserves a port for future use for Reservation-token.\n     * \n     * @param reserAddr the address to be reserved.\n     * @return false if it is already reserved, else true.\n     */\n    public boolean reservePort(TransportAddress reserAddr)\n    {\n        if(this.reservedAddress.contains(reserAddr))\n        {\n            return false;\n        }\n        else\n        {\n            this.reservedAddress.add(reserAddr);\n            return true;\n        }\n    }\n    \n    /**\n     * Function to get new Relay address.\n     * TODO : It has to be replaced with jitsi api.\n     * \n     * @param evenCompulsary\n     * @return a new RelayAddress\n     */\n    public TransportAddress getNewRelayAddress(boolean evenCompulsary,\n        Transport transport)\n    {\n        InetAddress ipAddress = null;\n        try\n        {\n            ipAddress = InetAddress.getLocalHost();\n        }\n        catch (UnknownHostException e)\n        {\n            e.printStackTrace();\n        }\n        TransportAddress possibleAddr =\n            new TransportAddress(ipAddress, nextPortNo++, transport);\n        int diff = evenCompulsary ? 2 : 1;\n        nextPortNo += (evenCompulsary && (nextPortNo%2)==0) ? 0 : 1;\n        while(this.reservedAddress.contains(possibleAddr) && nextPortNo < 65535)\n        {\n            nextPortNo += diff;\n            possibleAddr =\n                new TransportAddress(ipAddress, nextPortNo++, Transport.UDP);\n        }\n        return possibleAddr;\n    }\n    \n    /**\n     * Adds a new ConnectionId for the specified peerAddress and for the\n     * specified allocation.\n     * \n     * @param connectionId the connectionId created.\n     * @param peerAddress the peerAddress who initiated the TCP connection on\n     *            the relay address of the Allocation.\n     * @param allocation the allocation corresponding to the relay address on\n     *            which the connect request is received.\n     */\n    public void addUnAcknowlededConnectionId(int connectionId,\n        TransportAddress peerAddress, Allocation allocation)\n    {\n        FiveTuple peerTuple =\n            new FiveTuple(peerAddress,allocation.getRelayAddress(),\n                Transport.TCP);\n        this.unAcknowledgedConnId.add(connectionId);\n        this.peerConnToConnIdMap.put(\n            peerTuple, connectionId);\n        this.connIdToAllocMap.put(\n            connectionId, allocation);\n        allocation.addPeerTCPConnection(\n            connectionId, peerTuple);\n        logger.finest(\"Adding connectionId-\" + connectionId + \" for peerTuple-\"\n            + peerTuple + \" at allocation-\" + allocation);\n    }\n\n    /**\n     * Acknowledges the ConnectionID associated with the specified client data\n     * connection.\n     * \n     * @param connectionId the connectionId associated with the data connection.\n     * @param clientDataConnectionTuple the fiveTuple of the data connection.\n     */\n    public void acknowledgeConnectionId(int connectionId,\n        FiveTuple clientDataConnectionTuple)\n    {\n        if (!this.unAcknowledgedConnId.contains(connectionId))\n        {\n            throw new IllegalArgumentException(\"No such connectionId:\"\n                + connectionId + \" exists\");\n        }\n        else\n        {\n            this.unAcknowledgedConnId.remove(connectionId);\n            this.dataConnToConnIdMap.put(\n                clientDataConnectionTuple, connectionId);\n            Allocation allocation = this.connIdToAllocMap.get(connectionId);\n            allocation.addDataConnection(\n                connectionId, clientDataConnectionTuple);\n            logger.finest(\"Acknowledging connectiodId-\" + connectionId\n                + \" for client data conn-\" + clientDataConnectionTuple);\n        }\n    }\n    \n    /**\n     * Determines if the given ConnectionId is acknowledged or not.\n     * @param connectionID the connectionId to check.\n     * @return true if the specified connectionID is acknowledged, else false.\n     */\n    public boolean isUnacknowledged(int connectionID){\n        return this.unAcknowledgedConnId.contains(connectionID);\n    }\n    \n    /**\n     * Returns the Connection associated with the specified peerFiveTuple.\n     * \n     * @param peerFiveTuple the peerFiveTuple for which to get the ConnectionID.\n     * @return connectionID associated with the specified peerFiveTuple.\n     */\n    public int getConnectionIdForPeer(FiveTuple peerFiveTuple)\n    {\n        return this.peerConnToConnIdMap.get(peerFiveTuple);\n    }\n\n    /**\n     * Returns the ConnectionID associated with the specified\n     * \n     * @param dataConnTuple the five tuple of the data connection.\n     * @return the connectionId associated with the given data connection if\n     *         exists.\n     */\n    public int getConnectionIdForDataConn(FiveTuple dataConnTuple)\n    {\n        return this.dataConnToConnIdMap.get(dataConnTuple);\n    }\n    \n    /**\n     * Initialises and starts {@link #serverAllocationExpireThread} if\n     * necessary.\n     */\n    public void maybeStartServerAllocationExpireThread()\n    {\n        synchronized (serverAllocations)\n        {\n            if (!serverAllocations.isEmpty()\n                && (serverAllocationExpireThread == null))\n            {\n                Thread t = new Thread()\n                {\n                    @Override\n                    public void run()\n                    {\n                        runInServerAllocationExpireThread();\n                    }\n                };\n\n                t.setDaemon(true);\n                t.setName(getClass().getName()\n                    + \".serverAllocationExpireThread\");\n\n                boolean started = false;\n\n                serverAllocationExpireThread = t;\n                try\n                {\n                    t.start();\n                    started = true;\n                }\n                finally\n                {\n                    if (!started && (serverAllocationExpireThread == t))\n                        serverAllocationExpireThread = null;\n                }\n            }\n        }\n    }\n\n    /**\n     * Runs in {@link #serverAllocationExpireThread} and expires the\n     * <tt>Allocation</tt>s of this <tt>TurnStack</tt> and removes\n     * them from {@link #serverAllocations}.\n     */\n    private void runInServerAllocationExpireThread()\n    {\n        try\n        {\n            long idleStartTime = -1;\n\n            do\n            {\n                synchronized (serverAllocations)\n                {\n                    try\n                    {\n                        serverAllocations.wait(Allocation.DEFAULT_LIFETIME);\n                    }\n                    catch (InterruptedException ie)\n                    {\n                    }\n\n                    /*\n                     * Is the current Thread still designated to expire the\n                     * Allocations of this TurnStack?\n                     */\n                    if (Thread.currentThread() != serverAllocationExpireThread)\n                        break;\n\n                    long now = System.currentTimeMillis();\n\n                    /*\n                     * Has the current Thread been idle long enough to merit\n                     * disposing of it?\n                     */\n                    if (serverAllocations.isEmpty())\n                    {\n                        if (idleStartTime == -1)\n                            idleStartTime = now;\n                        else if (now - idleStartTime > 60 * 1000)\n                            break;\n                    }\n                    else\n                    {\n                        // Expire the Allocations of this TurnStack.\n\n                        idleStartTime = -1;\n\n                        for (Iterator<Allocation> i =\n                            serverAllocations.values().iterator(); i.hasNext();)\n                        {\n                            Allocation allocation = i.next();\n\n                            if (allocation == null)\n                            {\n                                i.remove();\n                            }\n                            else if (allocation.isExpired(now))\n                            {\n                                logger.finer(\"allocation \"+allocation+\" expired\");\n                                i.remove();\n                                allocation.expire();\n                            }\n                        }\n                    }\n                }\n            }\n            while (true);\n        }\n        finally\n        {\n            synchronized (serverAllocations)\n            {\n                if (serverAllocationExpireThread == Thread.currentThread())\n                    serverAllocationExpireThread = null;\n                /*\n                 * If serverAllocationExpireThread dies unexpectedly and yet it\n                 * is still necessary, resurrect it.\n                 */\n                if (serverAllocationExpireThread == null)\n                    maybeStartServerAllocationExpireThread();\n            }\n        }\n    }\n\n    \n    /**\n     * Method to check if the given message method is of Turn method.\n     * \n     * @param message\n     * @return true if message is of Turn method else false.\n     */\n    public static boolean isTurnMessage(Message message)\n    {\n        char method = message.getMessageType();\n        method = (char) (method & 0xfeef); // ignore the class\n\tlogger.finest(\"method extracted from \"\n\t\t+ (int) message.getMessageType() + \" is : \" + (int) method);\n        boolean isTurnMessage = false;\n        switch (method)\n        {\n        // Turn Specific Methods\n        case Message.TURN_METHOD_ALLOCATE:\n        case Message.TURN_METHOD_CHANNELBIND:\n        case Message.TURN_METHOD_CREATEPERMISSION:\n        case Message.TURN_METHOD_DATA:\n        case Message.TURN_METHOD_REFRESH:\n        case Message.TURN_METHOD_SEND:\n            // Turn TCP support Methods\n        case Message.TURN_METHOD_CONNECT:\n        case Message.TURN_METHOD_CONNECTION_BIND:\n        case Message.TURN_METHOD_CONNECTION_ATTEMPT:\n        case Message.STUN_METHOD_BINDING:\n            isTurnMessage = true;\n            break;\n        default:\n            isTurnMessage = false;\n        }\n        return isTurnMessage;\n\n    }\n    \n    /**\n     * Removes the username and Message Integrity attribute form Binding\n     * messages only.\n     * \n     * @param msg the Binding message from which the attribute is to be removed.\n     */\n    private void removeUsernameIntegrityFromBinding(Message msg)\n    {\n\tif((msg.getMessageType() & 0xfeef) != Message.STUN_METHOD_BINDING)\n\t{\n\t    return;\n\t}\n\tif(msg.containsAttribute(Attribute.USERNAME))\n\t{\n\t    msg.removeAttribute(Attribute.USERNAME);\n\t}\n\tif(msg.containsAttribute(Attribute.MESSAGE_INTEGRITY))\n\t{\n\t    msg.removeAttribute(Attribute.MESSAGE_INTEGRITY);\n\t}\n    }\n    \n    /**\n     * Initializes the turnstack with the registered users with username and their\n     * corresponding key.\n     */\n    public void initCredentials()\n    {\n\tString fileName = TurnStackProperties.DEFAULT_ACCOUNTS_FILE;\n\tFileReader fr;\n\ttry {\n\t    fr = new FileReader(fileName);\n\t    BufferedReader br = new BufferedReader(fr);\n\t    CredentialsManager cm = this.getCredentialsManager();\n\t    String line = null;\n\t    while((line = br.readLine())!=null)\n\t    {\n\t\tString[] tok = line.split(\":\");\n\t\tLongTermCredential ltc = new LongTermCredential(\n\t\t\ttok[0].getBytes(\"UTF-8\"), tok[1].getBytes(\"UTF-8\"));\n\t\tSystem.out.println(\"Adding - \" + new String(ltc.getUsername())\n\t\t\t+ \":\" + new String(ltc.getPassword()));\n\t\t// TODO replace with REALM instead of DEFAULT_REALM.\n\t\tLongTermCredentialSession ltcs = new LongTermCredentialSession(\n\t\t\tltc,\n\t\t\tTurnStackProperties.DEFAULT_REALM.getBytes(\"UTF-8\"));\n\t\tcm.registerAuthority(ltcs);\n\t    }\n\t    fr.close();\n\t    br.close();\n\t} catch (FileNotFoundException fnfe) {\n\t    logger.finest(\"File not found.\");\n\t}catch(IOException ioe){\n\t    logger.finest(\"Unable to read file.\");\n\t}\n\t\n    }\n    \n    /**\n     * Gets the component as RTP with TCP as transport also agent's stunStack as\n     * this TurnStack.\n     * \n     * @return component.\n     */\n    public Component getComponent()\n    {\n        if (this.component == null)\n        {\n            Agent agent = new Agent();\n            agent.setStunStack(this);\n            IceMediaStream stream = IceMediaStream.build(agent, \"Turn Server\");\n            this.component = Component.build(Component.RTP, stream);\n        }\n        return this.component;\n    }\n\n    /**\n     * Determines if the UDP messages are allowed in TURN server.\n     * \n     * @return true if UDP is allowed else false.\n     */\n    public boolean isUDPAllowed()\n    {\n        return this.udpAllowed;\n    }\n\n    /**\n     * Sets the udpAllowed variable to enable disable UDP messages.\n     * \n     * @param udpAllowed the boolean value to allow or disallow UDP messages.\n     */\n    public void setUDPAllowed(boolean udpAllowed)\n    {\n        this.udpAllowed = udpAllowed;\n    }\n\n    /**\n     * Determines if the TCP messages are allowed in TURN server.\n     * \n     * @return true if TCP is allowed else false.\n     */\n    public boolean isTCPAllowed()\n    {\n        return this.tcpAllowed;\n    }\n\n    /**\n     * Sets the tcpAllowed variable to enable disable TCP messages.\n     * \n     * @param tcpAllowed the boolean value to allow or disallow TCP messages.\n     */\n    public void setTCPAllowed(boolean tcpAllowed)\n    {\n        this.tcpAllowed = tcpAllowed;\n    }\n\n    /**\n     * Gets the allocation for the specified connectionID no.\n     * \n     * @param connectionId the connectionID for which to get the allocation.\n     * @return Allocation corresponding to specified connectionID or nul if not\n     *         found.\n     */\n    public Allocation getAllocationFromConnectionId(int connectionId)\n    {\n        return this.connIdToAllocMap.get(connectionId);\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/ClientChannelDataEventHandler.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.turnClient;\n\nimport java.io.*;\nimport java.util.logging.*  ;\n\nimport org.ice4j.*;\nimport org.ice4j.message.*;\nimport org.ice4j.stack.*;\n\nimport org.jitsi.turnserver.listeners.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Handles the incoming ChannelData message for Client from Server.\n * \n * @author Aakash Garg\n * \n */\npublic class ClientChannelDataEventHandler implements\n\tChannelDataEventHandler {\n    \n    /**\n     * The <tt>Logger</tt> used by the\n     * <tt>ServerChannelDataEventHandler</tt> class and its instances for\n     * logging output.\n     */\n    private static final Logger logger = Logger\n        .getLogger(ClientChannelDataEventHandler.class.getName());\n\n    /**\n     * The turnStack to call.\n     */\n    private TurnStack turnStack;\n \n    /**\n     * Default constructor.\n     */\n    public ClientChannelDataEventHandler()\n    {\n    }\n    \n    /**\n     * parametrised contructor.\n     * \n     * @param turnStack\n     *            the turnStack for this class.\n     */\n    public ClientChannelDataEventHandler(StunStack turnStack) \n    {\n\tif (turnStack instanceof TurnStack)\n        {\n            this.turnStack = (TurnStack) turnStack;\n        }\n        else\n        {\n            throw new IllegalArgumentException(\"This is not a TurnStack!\");\n        }\n    }\n\n    /**\n     * Sets the turnStack for this class.\n     * \n     * @param turnStack\n     *            the turnStack to set for this class.\n     */\n    public void setTurnStack(TurnStack turnStack)\n    {\n\tthis.turnStack = turnStack;\n    }\n    \n    /**\n     * Handles the ChannelDataMessageEvent.\n     * \n     * @param evt\n     *            the ChannelDataMessageEvent to handle/process.\n     */\n    @Override\n    public void handleMessageEvent(ChannelDataMessageEvent evt) \n    {\n\tif (logger.isLoggable(Level.FINER))\n        {\n            logger.setLevel(Level.FINEST);\n            logger.finer(\"Received ChannelData message \" + evt);\n        }\n\tChannelData channelData = evt.getChannelDataMessage();\n\tchar channelNo = channelData.getChannelNumber();\n\tbyte[] data = channelData.getData();\n\ttry {\n\t    String line = new String(data,\"UTF-8\");\n\t    System.out.println(line);\n\t} catch (UnsupportedEncodingException e) {\n\t    System.err.println(\"Unable to get back String.\");\n\t}\n/**\tSystem.out.println(\"Received a ChannelData message for \"\n\t\t+ (int) channelNo + \" , message : \" + Arrays.toString(data));\n    **/\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/InteractiveUdpPeer.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.turnClient;\n\nimport java.io.*;\nimport java.net.*;\n\nimport org.ice4j.*;\n\n/**\n * An interactive UDP peer client to send messages.\n * @author Aakash Garg\n *\n */\npublic class InteractiveUdpPeer {\n    \n    private static DatagramSocket sock;\n    \n    private static int serverPort = 15000;\n//    private static int serverPort = 49152;\n    \n    private static int clientPort = 11000;\n    /**\n     * @param args\n     * @throws IOException \n     */\n    public static void main(String[] args) throws IOException {\n\tString[] temp = {InetAddress.getLocalHost().toString(),\"\"+clientPort};\n\tif(args.length == 0)\n\t{\n\t    args = temp;\n\t}\n\tTransportAddress serverAddr = null;\n\tTransportAddress clientAddr = null;\n\tif(args.length==2)\n\t{\n\t    serverAddr = new TransportAddress(args[0],\n\t\t    Integer.parseInt(args[1]),Transport.UDP);\n\t    clientAddr = new TransportAddress(InetAddress.getLocalHost(),\n\t\t    12000,Transport.UDP);\n\t}\n\telse if(args.length==4)\n\t{\n\t    serverAddr = new TransportAddress(args[0],\n\t\t    Integer.parseInt(args[1]),Transport.UDP);\n\t    serverPort = Integer.parseInt(args[1]);\n\t    clientAddr = new TransportAddress(args[2],\n\t\t    Integer.parseInt(args[3]), Transport.UDP);\n\t    clientPort = Integer.parseInt(args[3]);\n\t}\n\telse\n\t{\n\t    throw new IllegalArgumentException(\"Please enter valid arguments.\");\n\t}\n\n\tsock = new DatagramSocket(clientPort,InetAddress.getLocalHost());\n\t/*\n\tThread recThread = getRecThread();\n\trecThread.start();\n\t*/\n/*\n\tFileReader fr = new FileReader(\n\t\t\"D:\\\\Eclipse\\\\turnserver\\\\samoleInputFile.txt\");\n*/\t//BufferedReader br = new BufferedReader(fr);\n\tBufferedReader br \n\t\t= new BufferedReader(new InputStreamReader(System.in));\n\tString line = null;\n\tSystem.out.println(\"Start typing message.\");\n\twhile((line = br.readLine())!=null)\n\t{\n\t    byte[] data = line.getBytes();\n\t    DatagramPacket pkt = new DatagramPacket(data, data.length,\n    \t\tInetAddress.getLocalHost(), serverPort);\n\t    sock.send(pkt);\n\t    System.out.println(\"Sent : \"+line);\n\t    \n\t    byte[] receiveData = new byte[1024];\n\t    DatagramPacket recPkt = new DatagramPacket(receiveData,\n\t\t    receiveData.length);\n\t    sock.receive(recPkt);\n\t    System.out.println(\"Recv : \" + getString(recPkt));\n\t}\n    }\n    \n    public static Thread getRecThread()\n    {\n\tRunnable recRun = new Runnable(){\n\t    @Override\n\t    public void run()\n\t    {\n\t\tbyte[] receiveData = new byte[1024];\n\t\tDatagramPacket recPkt = new DatagramPacket(receiveData,\n\t\t\treceiveData.length);\n\t\tSystem.out\n\t\t\t.println(\"Waiting for receiving data on \"\n\t\t\t\t+ sock.getLocalAddress().toString() + \":\"\n\t\t\t\t+ sock.getLocalPort());\n\t\ttry {\n\t\t    sock.receive(recPkt);\n\t\t\tSystem.out\n\t\t\t.println(\"Received Data : \" + getString(recPkt));\n\t\t} catch (IOException e) {\n\t\t    System.err.println(e.getMessage());\n\t\t}\n\t    }\n\t};\n\tThread thread  = new Thread(recRun);\n\treturn thread;\n    }\n    \n    public static String getString(DatagramPacket recPkt)\n    {\n\tbyte[] data = recPkt.getData();\n\tint len = recPkt.getLength();\n\tbyte[] recData = new byte[len];\n\tfor(int i=0; i<len; i++)\n\t{\n\t    recData[i] = data[i];\n\t}\n\ttry {\n\t    return new String(data,\"UTF-8\");\n\t} catch (UnsupportedEncodingException e) {\n\t   return null;\n\t}\n\t\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/StunClient.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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 org.jitsi.turnserver.turnClient;\n\nimport java.net.InetAddress;\n\nimport org.ice4j.*;\nimport org.ice4j.stack.*;\nimport org.ice4j.stunclient.*;\n\n/**\n * The class would be acting as a StunClient. The client runs on UDP initiates\n * displays network configuration <br>\n * Usage from command prompt <br>\n * \n * java org.ice4j.stunclient.StunCient stunserver.org stunPort <br>\n * (Displays the network configuration and port mapping using stunserver.org as\n * stunserver and stunPort as server's stun port<br>\n * * java org.ice4j.stunclient.StunCient N <br>\n * (chooses server from array of { \"stunserver.org\", \"stun.softjoys.com\",\n * \"stun.voiparound.com\", \"stun.voipbuster.com\", \"stun.voipstunt.com\",\n * \"stun.voxgratia.org\", \"stun.ekiga.net\", \"stun.ideasip.com\", \"stun.iptel.org\",\n * \"stun.rixtelecom.se\" })\n * \n * @author Aakash\n * \n */\n\npublic class StunClient\n{\n    /**\n     * @param args\n     */\n    public static StunDiscoveryReport getReport(String... args)\n        throws Exception\n    {\n        TransportAddress localAddr = null;\n        TransportAddress serverAddr = null;\n        Transport protocol = Transport.UDP;\n        int serverUdpPort = 3478;\n        String[] server =\n            { \"stunserver.org\", \"stun.softjoys.com\", \"stun.voiparound.com\",\n                \"stun.voipbuster.com\", \"stun.voipstunt.com\",\n                \"stun.voxgratia.org\", \"stun.ekiga.net\", \"stun.ideasip.com\",\n                \"stun.iptel.org\", \"stun.rixtelecom.se\" };\n\n        if (args.length == 4)\n        {\n            // uses args[0] and args[1] as server name and port and args[2] and\n            // args[3] as client ip and port\n            localAddr = new TransportAddress(args[2], Integer.valueOf(\n                args[3]).intValue(), protocol);\n            serverUdpPort = Integer.valueOf(\n                args[1]).intValue();\n            serverAddr = new TransportAddress(args[0], serverUdpPort, protocol);\n        }\n        else if (args.length == 2)\n        {\n            // uses args as server name and port\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            System.out.println(\"Sending request on \"+args[0]+\":\"+args[1]);\n            serverAddr = new TransportAddress(args[0], Integer.valueOf(\n                args[1]).intValue(), protocol);\n        }\n        else if (args.length == 1)\n        {\n            // chooses a server indexed by N\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            serverAddr =\n                new TransportAddress(server[Integer.parseInt(args[0])],\n                    serverUdpPort, protocol);\n            // serverAddr = new\n            // TransportAddress(InetAddress.getLocalHost(),serverUdpPort,protocol);\n            System.out.println(\"Stun Server - \"\n                + server[Integer.parseInt(args[0])] + \":\" + serverUdpPort);\n        }\n        else\n        {\n            // runs server running on same computer\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            // serverAddr = new TransportAddress(\n            // server[0],serverUdpPort,protocol);\n            serverAddr =\n                new TransportAddress(InetAddress.getLocalHost(), serverUdpPort,\n                    protocol);\n        }\n\n        NetworkConfigurationDiscoveryProcess addressDiscovery =\n            new NetworkConfigurationDiscoveryProcess(new StunStack(),\n                localAddr, serverAddr);\n\n        addressDiscovery.start();\n        StunDiscoveryReport report = addressDiscovery.determineAddress();\n        addressDiscovery.shutDown();\n        return report;\n    }\n\n    public static void main(String... args) throws Exception\n    {\n        StunDiscoveryReport report = StunClient.getReport(args);\n        System.out.println(report);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TcpPeer.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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 org.jitsi.turnserver.turnClient;\n\nimport java.io.IOException;\nimport java.net.DatagramPacket;\nimport java.net.InetAddress;\nimport java.net.Socket;\n\nimport org.ice4j.socket.IceTcpSocketWrapper;\n\npublic class TcpPeer\n{\n\n    public static void main(String... args)\n        throws IOException,\n        InterruptedException\n    {\n        System.out.println(\"sending request to server....\");\n        Socket client = new Socket(InetAddress.getLocalHost(), 15000);\n        System.out.println(\"successfully conneted from \"\n            + client.getLocalPort());\n        IceTcpSocketWrapper mySock = new IceTcpSocketWrapper(client);\n\n        byte[] data = new byte[1500];\n        DatagramPacket p = new DatagramPacket(data, 0);\n        System.out.println(\"Waiting for packet.\");\n        mySock.receive(p);\n        System.out.println(\"packet received\");\n        data = p.getData();\n        for (int i = 0; i < p.getLength(); i++)\n        {\n            System.out.print(String.format(\"%02X, \", data[i]));\n        }\n        System.out.println();\n        String returnMessage = \"Paras\";\n        p =\n            new DatagramPacket(returnMessage.getBytes(), returnMessage.length());\n        System.out.println(\"Sending return message-\"\n            + byteArrayToHex(p.getData()));\n        mySock.send(p);\n        System.out.println(\"Message Sent.\");\n        System.out.println(\"Thread going to sleep\");\n        Thread.sleep(100000);\n    }\n\n    private static String byteArrayToHex(byte[] data)\n    {\n        String arrayToHex = \"\";\n        for (int i = 0; i < data.length; i++)\n        {\n            arrayToHex += String.format(\"%02X, \", data[i]);\n        }\n        return arrayToHex;\n    }\n\n    public static void main2(String[] args)\n    {\n        String returnMessage = \"Paras\";\n        DatagramPacket p =\n            new DatagramPacket(returnMessage.getBytes(), returnMessage.length());\n        System.out.println(\"Sending return message-\"\n            + byteArrayToHex(p.getData()));\n        System.out.println(p.getLength() + \", \" + p.getOffset());\n\n    }\n\n}"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnAllocationClient.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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 org.jitsi.turnserver.turnClient;\n\nimport java.io.*;\nimport java.net.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.socket.*;\nimport org.ice4j.stack.*;\nimport org.ice4j.stunclient.*;\n\nimport org.jitsi.turnserver.collectors.AllocationResponseCollector;\nimport org.jitsi.turnserver.listeners.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to run Allocation Client.\n * \n * @author Aakash Garg\n *\n */\npublic class TurnAllocationClient\n{\n    private static BlockingRequestSender requestSender;\n    private static IceUdpSocketWrapper sock;\n    private static TurnStack turnStack;\n    private static TransportAddress localAddress;\n    private static TransportAddress serverAddress;\n    private static boolean started;\n    \n    /**\n     * The instance that should be notified when an incoming UDP message has\n     * been processed and ready for delivery\n     */\n    private PeerUdpMessageEventHandler peerUdpMessageEventHandler;\n\n    /**\n     * The instance that should be notified when an incoming ChannelData message\n     * has been processed and ready for delivery\n     */\n    private ChannelDataEventHandler channelDataEventHandler;\n\n    /**\n     * @param args\n     * @throws IOException \n     * @throws StunException \n     * @throws InterruptedException \n     */\n    public static void main(String[] args) throws IOException, StunException,\n\t    InterruptedException\n    {\n        String[] temp = {InetAddress.getLocalHost().getHostAddress(),\"3478\"};\n//        String[] temp = {\"176.31.40.85\",\"3478\"};\n        args = temp;\n       Transport protocol = Transport.UDP;\n        \n        // uses args as server name and port\n        localAddress =\n            new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n        serverAddress =\n            new TransportAddress(args[0], Integer.valueOf(\n                args[1]).intValue(), protocol);\n        System.out.println(\"Client adress : \"+localAddress);\n        System.out.println(\"Server adress : \"+serverAddress);\n        start();\n        StunMessageEvent evt = null;\n        evt = sendAllocationRequest(localAddress,serverAddress);\n        evt = sendCreatePermissionRequest(9999);\n        evt = sendCreatePermissionRequest(9999);\n        evt = sendCreatePermissionRequest(11000);\n        \n        TransportAddress peerAddr \n            = new TransportAddress(InetAddress.getLocalHost(), 11000, protocol);\n        \n        evt = sendChannelBindRequest((char) 0x4000,peerAddr);\n        sendChannelDataMessage();\n        System.out.println(\"Starting interactive communication.\");\n        doInteractiveComm();\n/*        System.out.println(\"Thread will now sleep.\");\n        Thread.sleep(600*1000);\n*/        \n        shutDown();\n    }\n\n    public static StunMessageEvent sendAllocationRequest(\n        TransportAddress localAddr, TransportAddress serverAddress)\n        throws IOException\n  {\n        Request request = MessageFactory.createAllocateRequest();\n        \n        RequestedTransportAttribute requestedTransportAttribute =\n            AttributeFactory.createRequestedTransportAttribute(\n                RequestedTransportAttribute.UDP);\n        \n        request.putAttribute(requestedTransportAttribute);\n        \n        StunMessageEvent evt = null;\n        try\n        {\n\t    AllocationResponseCollector allocResCollec \n\t    \t= new AllocationResponseCollector(turnStack);\n/*\t    turnStack.sendRequest(request, serverAddress, localAddress,\n\t\t    allocResCollec);\n*/            evt = requestSender.sendRequestAndWaitForResponse(\n                    request, serverAddress);\n\t\tallocResCollec.processResponse((StunResponseEvent) evt);\n        }\n        catch (Exception ex)\n        {\n            //this shouldn't happen since we are the ones that created the\n            //request\n            ex.printStackTrace();\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if(evt != null)\n            System.out.println(\"Allocation TEST res=\"\n                               +(int)(evt.getMessage().getMessageType())\n                               +\" - \"+ evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to Allocation TEST.\");\n        return evt;\n    }\n    \n    public static StunMessageEvent sendCreatePermissionRequest(int peerPort)\n        throws IOException, StunException\n    {\n        System.out.println();\n        TransportAddress peerAddr = new TransportAddress(\n                                        serverAddress.getAddress(),\n                                        peerPort,\n                                        Transport.UDP);\n        TransactionID tran = TransactionID.createNewTransactionID();\n        System.out.println(\"Create request for : \"+peerAddr);\n        Request request  \n            = MessageFactory.createCreatePermissionRequest(\n                peerAddr,\n                tran.getBytes());\n        StunMessageEvent evt = null;\n        System.out.println(\"Permission tran : \"+tran);\n        try\n        {\n            evt = requestSender.sendRequestAndWaitForResponse(\n                    request, serverAddress,tran);\n        }\n        catch (StunException ex)\n        {\n            //this shouldn't happen since we are the ones that created the\n            //request\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if(evt != null)\n            System.out.println(\"Permission TEST res=\"\n                               +(int)(evt.getMessage().getMessageType())\n                               +\" - \"+ evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to Permission TEST.\");\n       \n        return evt;\n    }\n    \n    public static StunMessageEvent sendChannelBindRequest(\n                    char channelNo, \n                    TransportAddress peerAddress)\n        throws IOException, StunException\n    {\n        System.out.println();\n        System.out.println(\"ChannelBind request for : \"+peerAddress\n                    +\" on \"+(int)channelNo);\n        TransactionID tran = TransactionID.createNewTransactionID();\n        Request request\n            = MessageFactory.createChannelBindRequest(\n                                                        channelNo,\n                                                        peerAddress,\n                                                        tran.getBytes());\n        char cNo =\n            ((ChannelNumberAttribute) (request\n                .getAttribute(Attribute.CHANNEL_NUMBER))).getChannelNumber();\n        TransportAddress pAddr =\n            ((XorPeerAddressAttribute) (request\n                .getAttribute(Attribute.XOR_PEER_ADDRESS))).getAddress();\n        \n        XorMappedAddressAttribute mappedAddr =\n            AttributeFactory.createXorMappedAddressAttribute(\n                localAddress, tran.getBytes());\n        //mappedAddr.setAddress(mappedAddr.getAddress(), tran.getBytes());\n        System.out.println(\">\"+mappedAddr.getAddress());\n        request.putAttribute(mappedAddr);\n        System.out.println(\"input mappedAddress : \"+mappedAddr.getAddress());\n        \n        XorMappedAddressAttribute retMapAddr\n            = (XorMappedAddressAttribute) (request\n            .getAttribute(Attribute.XOR_MAPPED_ADDRESS));\n        \n        TransportAddress mAddr =\n            (retMapAddr).getAddress();\n        System.out.println(\"output mappedAddress : \"+mAddr.getHostAddress());\n        \n        System.out.println(\"Retrived ChannelBind request is : \"+pAddr\n            +\" on \"+(int)cNo);\n\n        StunMessageEvent evt = null;\n        System.out.println(\"ChannelBind tran : \"+tran);\n        try\n        {\n            evt = requestSender.sendRequestAndWaitForResponse(\n                    request, serverAddress,tran);\n        }\n        catch (StunException ex)\n        {\n            //this shouldn't happen since we are the ones that created the\n            //request\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if(evt != null)\n            System.out.println(\"ChannelBind TEST res=\"\n                               +evt.getRemoteAddress().toString()\n                               +\" - \"+ evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to ChannelBind TEST.\");\n       \n        return evt;\n    }\n    \n    public static void sendChannelDataMessage() throws StunException,\n\t    IOException\n    {\n\tbyte[] message = {0xa,0xb};\n\tChannelData channelData = new ChannelData();\n\tchannelData.setChannelNumber((char)0x4000);\n\tchannelData.setData(message);\n\tturnStack.sendChannelData(channelData, serverAddress, localAddress);\n\tSystem.out.println(\"ChannelData message sent.\");\n    }\n    \n    /**\n     * Puts the discoverer into an operational state.\n     * @throws IOException if we fail to bind.\n     * @throws StunException if the stun4j stack fails start for some reason.\n     */\n    public static void start()\n        throws IOException, StunException\n    {\n\tClientChannelDataEventHandler channelDataHandler \n\t\t= new ClientChannelDataEventHandler();\n\tturnStack = new TurnStack(null, channelDataHandler);\n        channelDataHandler.setTurnStack(turnStack);\n        sock = new IceUdpSocketWrapper(\n            new SafeCloseDatagramSocket(localAddress));\n        turnStack.addSocket(sock);\n\n        DataIndicationListener dataIndListener = \n        \tnew DataIndicationListener(turnStack);\n        dataIndListener.setLocalAddress(localAddress);\n        dataIndListener.start();\n        \n        requestSender = new BlockingRequestSender(turnStack, localAddress);\n\n        started = true;\n    }\n    \n    \n    public static void doInteractiveComm() throws IOException, StunException\n    {\n\tBufferedReader br \n\t\t= new BufferedReader(new InputStreamReader(System.in));\n    System.out.println(\"Started interaction start typing message\");\n\tString line = br.readLine();\n\tSystem.out.println(\"My first message : \"+line);\n\twhile(line!=null)\n\t{\n\t    byte[] data = line.getBytes();\n\t    TransactionID tran = TransactionID.createNewTransactionID();\n\t    TransportAddress peerAddress = new TransportAddress(\n\t\t    InetAddress.getLocalHost(), 11000, Transport.UDP);\n\t    Indication ind = MessageFactory.createSendIndication(peerAddress,\n\t\t    data, tran.getBytes());\n\t    System.out.println(\"Trying to send message to server\");\n\t    turnStack.sendIndication(ind, serverAddress, localAddress);\n\t    System.out.println(\"message sent\");\n\t    \n\t    System.out.println(\"Type a new message : \");\n\t    line = br.readLine();\n\t}\n    }\n\n    /**\n     * Shuts down the underlying stack and prepares the object for garbage\n     * collection.\n     */\n    public static void shutDown()\n    {\n        turnStack.removeSocket(localAddress);\n        sock.close();\n        sock = null;\n\n        localAddress  = null;\n        requestSender = null;\n\n        started = false;\n    }\n    \n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnClient.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.turnClient;\n\nimport java.net.InetAddress;\n\nimport org.ice4j.Transport;\nimport org.ice4j.TransportAddress;\nimport org.ice4j.stack.StunStack;\nimport org.ice4j.stunclient.NetworkConfigurationDiscoveryProcess;\nimport org.ice4j.stunclient.StunDiscoveryReport;\n\n/**\n * The class would be acting as a TurnClient. The client runs on UDP initiates\n * displays network configuration <br>\n * Usage from command prompt <br>\n * \n * java org.ice4j.Turnclient.TurnCient Turnserver.org TurnPort <br>\n * (Displays the network configuration and port mapping using Turnserver.org as\n * Turnserver and TurnPort as server's Turn port<br>\n * * java org.ice4j.Turnclient.TurnCient N <br>\n * (chooses server from array of { \"Turnserver.org\", \"Turn.softjoys.com\",\n * \"Turn.voiparound.com\", \"Turn.voipbuster.com\", \"Turn.voipTurnt.com\",\n * \"Turn.voxgratia.org\", \"Turn.ekiga.net\", \"Turn.ideasip.com\", \"Turn.iptel.org\",\n * \"Turn.rixtelecom.se\" })\n * \n * @author Aakash\n * \n */\n\npublic class TurnClient\n{\n    /**\n     * @param args\n     */\n    public static StunDiscoveryReport getReport(String... args)\n        throws Exception\n    {\n        TransportAddress localAddr = null;\n        TransportAddress serverAddr = null;\n        Transport protocol = Transport.UDP;\n        int serverUdpPort = 3478;\n        \n        String[] server =\n            { \"stunserver.org\", \"stun.softjoys.com\", \"stun.voiparound.com\",\n                \"stun.voipbuster.com\", \"stun.voipstunt.com\",\n                \"stun.voxgratia.org\", \"stun.ekiga.net\", \"stun.ideasip.com\",\n                \"stun.iptel.org\", \"stun.rixtelecom.se\" };\n\n        String[] temp = {\"120.57.226.103\",\"26768\"};\n        String[] temp2 = {\"127.0.0.1\",\"3478\"};\n        args  = temp2;\n        if (args.length == 4)\n        {\n            // uses args[0] and args[1] as server name and port and args[2] and\n            // args[3] as client ip and port\n            localAddr = new TransportAddress(args[2], Integer.valueOf(\n                args[3]).intValue(), protocol);\n            serverUdpPort = Integer.valueOf(\n                args[1]).intValue();\n            serverAddr = new TransportAddress(args[0], serverUdpPort, protocol);\n        }\n        else if (args.length == 2)\n        {\n            // uses args as server name and port\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            serverAddr = new TransportAddress(args[0], Integer.valueOf(\n                args[1]).intValue(), protocol);\n        }\n        else if (args.length == 1)\n        {\n            // chooses a server indexed by N\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            serverAddr =\n                new TransportAddress(server[Integer.parseInt(args[0])],\n                    serverUdpPort, protocol);\n            // serverAddr = new\n            // TransportAddress(InetAddress.getLocalHost(),serverUdpPort,protocol);\n            System.out.println(\"Stun Server - \"\n                + server[Integer.parseInt(args[0])] + \":\" + serverUdpPort);\n        }\n        else\n        {\n            // runs server running on same computer\n            localAddr =\n                new TransportAddress(InetAddress.getLocalHost(), 5678, protocol);\n            // serverAddr = new TransportAddress(\n            // server[0],serverUdpPort,protocol);\n            serverAddr =\n                new TransportAddress(InetAddress.getLocalHost(), serverUdpPort,\n                    protocol);\n        }\n\n        NetworkConfigurationDiscoveryProcess addressDiscovery =\n            new NetworkConfigurationDiscoveryProcess(new StunStack(),\n                localAddr, serverAddr);\n\n        addressDiscovery.start();\n        StunDiscoveryReport report = addressDiscovery.determineAddress();\n        addressDiscovery.shutDown();\n        return report;\n    }\n\n    public static void main(String... args) throws Exception\n    {\n        StunDiscoveryReport report = TurnClient.getReport(args);\n        System.out.println(report);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnTcpAllocationClient.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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 org.jitsi.turnserver.turnClient;\n\nimport java.io.*;\nimport java.net.*;\n\nimport org.ice4j.*;\nimport org.ice4j.attribute.*;\nimport org.ice4j.message.*;\nimport org.ice4j.socket.*;\nimport org.ice4j.stack.*;\nimport org.ice4j.stunclient.*;\n\nimport org.jitsi.turnserver.collectors.*;\nimport org.jitsi.turnserver.listeners.*;\nimport org.jitsi.turnserver.stack.*;\n\n/**\n * Class to run Allocation Client over TCP.\n * \n * @author Aakash Garg\n * \n */\npublic class TurnTcpAllocationClient\n{\n    private static BlockingRequestSender requestSender;\n\n    private static IceTcpSocketWrapper sock;\n\n    private static TurnStack turnStack;\n\n    private static TransportAddress localAddress;\n\n    private static TransportAddress serverAddress;\n\n    private static boolean started;\n\n    private static Socket tcpSocketToServer = null;\n\n    /**\n     * The instance that should be notified when an incoming TCP message has\n     * been processed and ready for delivery\n     */\n    private PeerUdpMessageEventHandler peerUdpMessageEventHandler;\n\n    /**\n     * Puts the discoverer into an operational state.\n     * \n     * @throws IOException if we fail to bind.\n     * @throws StunException if the stun4j stack fails start for some reason.\n     */\n    public static void start(Transport protocol) throws IOException,\n        StunException\n    {\n        sock = new IceTcpSocketWrapper(tcpSocketToServer);\n        System.out.println(\"Adding an new TCP connection to : \"\n            + serverAddress.getHostAddress());\n\n        localAddress =\n            new TransportAddress(InetAddress.getLocalHost(),\n                tcpSocketToServer.getLocalPort(), protocol);\n        System.out.println(\"Client adress : \" + localAddress);\n        System.out.println(\"Server adress : \" + serverAddress);\n\n        ClientChannelDataEventHandler channelDataHandler =\n            new ClientChannelDataEventHandler();\n        turnStack = new TurnStack(null, channelDataHandler);\n        channelDataHandler.setTurnStack(turnStack);\n        \n        turnStack.addSocket(sock);\n\n        requestSender = new BlockingRequestSender(turnStack, localAddress);\n\n        ConnectionAttemptIndicationListener connectionAttemptIndicationListener =\n            new ConnectionAttemptIndicationListener(turnStack/*,requestSender*/);\n        connectionAttemptIndicationListener.setLocalAddress(localAddress);\n        connectionAttemptIndicationListener.start();\n        \n        started = true;\n    }\n\n    /**\n     * @param args\n     * @throws IOException\n     * @throws StunException\n     * @throws InterruptedException\n     */\n    public static void main(String[] args) throws IOException, StunException,\n        InterruptedException\n    {\n        String[] temp =\n        { InetAddress.getLocalHost().toString(), \"3478\" };\n        args = temp;\n        Transport protocol = Transport.TCP;\n\n        // uses args as server name and port\n        serverAddress =\n            new TransportAddress(InetAddress.getLocalHost(), Integer.valueOf(\n                args[1]).intValue(), protocol);\n\n        tcpSocketToServer = new Socket(serverAddress.getHostAddress(), 3478);\n        System.out.println(\"Local port chosen : \" + tcpSocketToServer.getLocalPort());\n\n        start(protocol);\n        StunMessageEvent evt = null;\n        evt = sendAllocationRequest(\n            localAddress, serverAddress);\n        evt = sendCreatePermissionRequest(9999);\n        // evt = sendCreatePermissionRequest(9999);\n        // evt = sendCreatePermissionRequest(11000);\n        // evt = sendConnectRequest(9999);\n\n        TransportAddress peerAddr =\n            new TransportAddress(InetAddress.getLocalHost(), 11000, protocol);\n\n        Thread.sleep(600 * 1000);\n\n        shutDown();\n    }\n\n    public static StunMessageEvent sendAllocationRequest(\n        TransportAddress localAddr, TransportAddress serverAddress)\n        throws IOException\n    {\n        Request request = MessageFactory.createAllocateRequest();\n\n        RequestedTransportAttribute requestedTransportAttribute =\n            AttributeFactory\n                .createRequestedTransportAttribute(RequestedTransportAttribute.TCP);\n\n        request.putAttribute(requestedTransportAttribute);\n        System.out.println(\"Message type : \" + (int) request.getMessageType());\n        StunMessageEvent evt = null;\n        try\n        {\n            AllocationResponseCollector allocResCollec =\n                new AllocationResponseCollector(turnStack);\n            /*\n             * turnStack.sendRequest(request, serverAddress, localAddress,\n             * allocResCollec);\n             */\n            evt = requestSender.sendRequestAndWaitForResponse(\n                request, serverAddress);\n            allocResCollec.processResponse((StunResponseEvent) evt);\n        }\n        catch (Exception ex)\n        {\n            // this shouldn't happen since we are the ones that created the\n            // request\n            ex.printStackTrace();\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if (evt != null)\n            System.out.println(\"Allocation TEST res=\"\n                + (int) (evt.getMessage().getMessageType()) + \" - \"\n                + evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to Allocation TEST.\");\n        return evt;\n    }\n\n    public static StunMessageEvent sendCreatePermissionRequest(int peerPort)\n        throws IOException, StunException\n    {\n        System.out.println();\n        TransportAddress peerAddr =\n            new TransportAddress(serverAddress.getAddress(), peerPort,\n                Transport.TCP);\n        TransactionID tran = TransactionID.createNewTransactionID();\n        System.out.println(\"Create request for : \" + peerAddr);\n        Request request = MessageFactory.createCreatePermissionRequest(\n            peerAddr, tran.getBytes());\n        StunMessageEvent evt = null;\n        System.out.println(\"Permission tran : \" + tran);\n        try\n        {\n            evt = requestSender.sendRequestAndWaitForResponse(\n                request, serverAddress, tran);\n        }\n        catch (StunException ex)\n        {\n            // this shouldn't happen since we are the ones that created the\n            // request\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if (evt != null)\n            System.out.println(\"Permission TEST res=\"\n                + (int) (evt.getMessage().getMessageType()) + \" - \"\n                + evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to Permission TEST.\");\n\n        return evt;\n    }\n\n    public static StunMessageEvent sendConnectRequest(int peerPort)\n        throws IOException, StunException\n    {\n        System.out.println();\n        TransportAddress peerAddr =\n            new TransportAddress(serverAddress.getAddress(), peerPort,\n                Transport.TCP);\n        TransactionID tran = TransactionID.createNewTransactionID();\n        System.out.println(\"Connect request for : \" + peerAddr);\n        Request request = MessageFactory.createConnectRequest(\n            peerAddr, tran.getBytes());\n        request.setTransactionID(tran.getBytes());\n        StunMessageEvent evt = null;\n        System.out.println(\"Connect Req tran : \" + tran);\n        try\n        {\n            evt = requestSender.sendRequestAndWaitForResponse(\n                request, serverAddress, tran);\n        }\n        catch (StunException ex)\n        {\n            // this shouldn't happen since we are the ones that created the\n            // request\n            System.out.println(\"Internal Error. Failed to encode a message\");\n            return null;\n        }\n\n        if (evt != null)\n            System.out.println(\"Connect request TEST res=\"\n                + (int) (evt.getMessage().getMessageType()) + \" - \"\n                + evt.getRemoteAddress().getHostAddress());\n        else\n            System.out.println(\"NO RESPONSE received to Connect Request TEST.\");\n\n        return evt;\n    }\n\n    public static void doInteractiveComm() throws IOException, StunException\n    {\n        System.out.println(\"---->Interactve Communication started<---------\");\n        BufferedReader br =\n            new BufferedReader(new InputStreamReader(System.in));\n        String line = null;\n        while ((line = br.readLine()) != null)\n        {\n            byte[] data = line.getBytes();\n            TransactionID tran = TransactionID.createNewTransactionID();\n            TransportAddress peerAddress =\n                new TransportAddress(InetAddress.getLocalHost(), 11000,\n                    Transport.TCP);\n            Indication ind = MessageFactory.createSendIndication(\n                peerAddress, data, tran.getBytes());\n            turnStack.sendIndication(\n                ind, serverAddress, localAddress);\n        }\n    }\n\n    /**\n     * Shuts down the underlying stack and prepares the object for garbage\n     * collection.\n     */\n    public static void shutDown()\n    {\n        turnStack.removeSocket(localAddress);\n        sock.close();\n        sock = null;\n\n        localAddress = null;\n        requestSender = null;\n\n        started = false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/resources/TurnServer.propertes",
    "content": "org.jitsi.turnserver.udp_port = 3478;\norg.jitsi.turnserver.max_port = 65535;\norg.jitsi.turnserver.min_port = 49152;\norg.jitsi.turnserver.unpriv_user = ;\norg.jitsi.turnserver.max_client = ;\norg.jitsi.turnserver.max_relay_per_username = ;\norg.jitsi.turnserver.allocation_lifetime = ;\norg.jitsi.turnserver.nonce_key = 79897BC1042DF24AAE2FACFF9E2A6093;\norg.jitsi.turnserver.ca_file = ;\norg.jitsi.turnserver.cert_file = ;\norg.jitsi.turnserver.private_key_file = ;\norg.jitsi.turnserver.realm = ;\norg.jitsi.turnserver.bandwidth_per_allocation = ;\norg.jitsi.turnserver.restricted_bandwidth = ;\norg.jitsi.turnserver.account_method = ;\norg.jitsi.turnserver.account_file = ;"
  },
  {
    "path": "src/main/resources/accounts.txt",
    "content": "JitsiGsocStudent:8156CE4E8499609C34C641E2C2904171\nJitsiGsocMentor:654714090BC4348274203EE55EEFBB26\n"
  },
  {
    "path": "src/main/resources/logging.properties",
    "content": "############################################################\n#  Default Logging Configuration File\n#\n# You can use a different file by specifying a filename\n# with the java.util.logging.config.file system property.\n# For example java -Djava.util.logging.config.file=myfile\n############################################################\n\n############################################################\n#  Global properties\n############################################################\n\n# \"handlers\" specifies a comma separated list of log Handler\n# classes.  These handlers will be installed during VM startup.\n# Note that these classes must be on the system classpath.\n# By default we only configure a ConsoleHandler, which will only\n# show messages at the INFO and above levels.\nhandlers= java.util.logging.ConsoleHandler\n\n\n# To also add the FileHandler, use the following line instead.\n#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler\n\n# Default global logging level.\n# This specifies which kinds of events are logged across\n# all loggers.  For any given facility this global level\n# can be overriden by a facility specific level\n# Note that the ConsoleHandler also has a separate level\n# setting to limit messages printed to the console.\n.level= ALL\n\n############################################################\n# Handler specific properties.\n# Describes specific configuration info for Handlers.\n############################################################\n\n# default file output is in user's home directory.\n\n\n\n# Note that the level for the console handler may be modified by the application.\n# Also note that you won't see any logs with a Level Lower than this one.\njava.util.logging.ConsoleHandler.level = ALL\njava.util.logging.ConsoleHandler.formatter = org.ice4j.util.Ice4jLogFormatter\n\n\n############################################################\n# Facility specific properties.\n# Provides extra control for each logger.\n############################################################\n\n# Things coming from ice4j\norg.ice4j.level = INFO\ntest.level = INFO\n#org.ice4j.ice.checks.levell = FINEST\n#org.ice4j.ice.ConnectivityCheckClient.level = FINER\n\n"
  },
  {
    "path": "src/test/java/org/jitsi/turnserver/client/ClientTest.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.client;\n\nimport static org.junit.Assert.*;\n\nimport java.io.*;\nimport java.net.*;\nimport java.util.*;\nimport java.util.concurrent.*;\n\nimport org.jitsi.turnserver.*;\nimport org.jitsi.turnserver.stack.*;\nimport org.junit.*;\nimport org.ice4j.*;\nimport org.ice4j.ice.*;\nimport org.ice4j.ice.harvest.*;\nimport org.ice4j.socket.*;\nimport org.ice4j.stack.*;\nimport org.ice4j.stunclient.*;\n\n/**\n * This tests clients against a local turnserver.\n *\n * @author Paul Gregoire\n */\npublic class ClientTest\n{\n\n    private static ExecutorService executor;\n\n    // holder for reference to the running turnserver\n    private static Future<?> future;\n\n    private static TurnServer turnServer;\n\n    private static TransportAddress serverAddr;\n\n    // goggle stun for testing purposes\n    TransportAddress googAddr = new TransportAddress(\"stun.l.google.com\",\n                    19302, Transport.UDP);\n\n    @Before\n    public void setUp() throws Exception\n    {\n        // instance an executor\n        executor = Executors.newCachedThreadPool();\n        // create an address for binding\n        serverAddr =\n            new TransportAddress(getLocalAddress(), 3478, Transport.UDP);\n        // instance a turnserver\n        turnServer = new TurnServer(serverAddr);\n        // start the server\n        future = executor.submit(new Runnable()\n        {\n            public void run()\n            {\n                try\n                {\n                    turnServer.start();\n                }\n                catch (TurnException e)\n                {\n                    e.printStackTrace();\n                }\n                catch (IOException e)\n                {\n                    e.printStackTrace();\n                }\n                do\n                {\n                    try\n                    {\n                        Thread.sleep(1000L);\n                    }\n                    catch (InterruptedException e)\n                    {\n                        // e.printStackTrace();\n                    }\n                } while (turnServer.isStarted());\n            }\n        });\n    }\n\n    @After\n    public void tearDown() throws Exception\n    {\n        // stop the server\n        turnServer.shutDown();\n        // cancel the future\n        future.cancel(true);\n    }\n\n    @Test\n    public void testUDPClient() throws Exception\n    {\n        // create a client address for binding\n        TransportAddress clientAddr =\n            new TransportAddress(getLocalAddress(), 5678, Transport.UDP);\n        // create a discover process\n        NetworkConfigurationDiscoveryProcess addressDiscovery =\n            new NetworkConfigurationDiscoveryProcess(new StunStack(),\n                            clientAddr, serverAddr);\n        // start discovery process\n        addressDiscovery.start();\n        // pull the report\n        StunDiscoveryReport report = addressDiscovery.determineAddress();\n        System.out.println(report);\n        assertNotNull(report.getPublicAddress());\n        // stop discovery process\n        addressDiscovery.shutDown();\n    }\n\n    @Test\n    public void testIceMediaStream() throws Exception\n    {\n        // instance a control-side\n        Future<?> ctrl = executor.submit(new ControlClient());\n        // instance an end point / subscriber\n        Future<?> end = executor.submit(new EndpointClient());\n        // sleep this thread\n        Thread.sleep(3000L);\n        // kill the clients\n        ctrl.cancel(true);\n        end.cancel(true);\n    }\n\n    /**\n     * Utility method to provide a local IP address for current interfaces.\n     * \n     * @return local address or default of 127.0.0.1\n     */\n    private String getLocalAddress()\n    {\n        Enumeration<NetworkInterface> ifaces;\n        try\n        {\n            ifaces = NetworkInterface.getNetworkInterfaces();\n            while (ifaces.hasMoreElements())\n            {\n                NetworkInterface iface =\n                    (NetworkInterface) ifaces.nextElement();\n                Enumeration<InetAddress> iaddresses = iface.getInetAddresses();\n                while (iaddresses.hasMoreElements())\n                {\n                    InetAddress iaddress =\n                        (InetAddress) iaddresses.nextElement();\n                    if (!iaddress.isLoopbackAddress()\n                                    && !iaddress.isLinkLocalAddress()\n                                    && !iaddress.isSiteLocalAddress())\n                    {\n                        String hostAddr = iaddress.getHostAddress();\n                        return hostAddr != null ? hostAddr : iaddress\n                                        .getHostName();\n                    }\n                }\n            }\n            String localhostAddr = InetAddress.getLocalHost().getHostAddress();\n            return localhostAddr != null ? localhostAddr : InetAddress\n                            .getLocalHost().getHostName();\n        }\n        catch (SocketException e)\n        {\n            e.printStackTrace();\n        }\n        catch (UnknownHostException e)\n        {\n            e.printStackTrace();\n        }\n        return \"127.0.0.1\";\n    }\n\n    class ControlClient implements Runnable\n    {\n\n        public void run()\n        {\n            // instance an ICE agent\n            Agent agent = new Agent();\n            agent.setControlling(true);\n            agent.setTrickling(true);\n            String user = agent.getLocalUfrag();\n            String passwd = agent.getLocalPassword();\n            System.out.printf(\"Control - user: %s passwd: %s\\n\", user, passwd);\n            // add havesters\n            // agent.addCandidateHarvester(new\n            // StunCandidateHarvester(googAddr));\n            agent.addCandidateHarvester(new TurnCandidateHarvester(serverAddr));\n            System.out.printf(\"Agent state: %s\\n\", agent.getState());\n            // add a stream\n            IceMediaStream stream = agent.getStream(\"junit\");\n            assertNull(stream);\n            stream = agent.createMediaStream(\"junit\");\n            assertNotNull(stream);\n            // create a data component\n            Component rtp = null;\n            try\n            {\n                rtp =\n                    agent.createComponent(stream, Transport.UDP, 6000, 6000,\n                                    6016);\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n            }\n            for (CandidateHarvester harvester : agent.getHarvesters())\n            {\n                System.out.printf(\"Harvesting for rtp via %s\\n\", harvester);\n                try\n                {\n                    Collection<LocalCandidate> candidates =\n                        harvester.harvest(rtp);\n                    if (candidates.isEmpty())\n                    {\n                        System.out.println(\"No candidates found\");\n                        continue;\n                    }\n                    System.out.printf(\"Harvested candidates: %s\\n\", candidates);\n                    for (LocalCandidate candidate : candidates)\n                    {\n                        rtp.addLocalCandidate(candidate);\n                    }\n                    break;\n                }\n                catch (Exception e)\n                {\n                    e.printStackTrace();\n                }\n            }\n            // start connection establishment\n            agent.startConnectivityEstablishment();\n            IceProcessingState state;\n            while ((state = agent.getState()) != IceProcessingState.TERMINATED)\n            {\n                System.out.printf(\n                                \"Control connectivity establishment in process, state: %s\\n\",\n                                state);\n                try\n                {\n                    if (state == IceProcessingState.FAILED) { throw new Exception(\n                                    \"ICE connectivity failed\"); }\n                    // sleep until ICE terminates or fails\n                    Thread.sleep(500);\n                }\n                catch (Exception e)\n                {\n                    e.printStackTrace();\n                    agent.free();\n                    break;\n                }\n            }\n            // get candidates\n            CandidatePair rtpPair =\n                agent.getStream(\"junit\").getComponent(Component.RTP)\n                                .getSelectedPair();\n            System.out.printf(\"Control IP: %s\\n\", rtpPair.getRemoteCandidate()\n                            .getTransportAddress());\n            IceUdpSocketWrapper wrapper =\n                new IceUdpSocketWrapper(rtpPair.getDatagramSocket());\n            // wrapper.send(packet);\n        }\n    }\n\n    class EndpointClient implements Runnable\n    {\n\n        public void run()\n        {\n            // instance an ICE agent\n            Agent agent = new Agent();\n            agent.setControlling(false);\n            agent.setTrickling(true);\n            String user = agent.getLocalUfrag();\n            String passwd = agent.getLocalPassword();\n            System.out.printf(\"Endpoint - user: %s passwd: %s\\n\", user, passwd);\n            // add havesters\n            // agent.addCandidateHarvester(new\n            // StunCandidateHarvester(googAddr));\n            agent.addCandidateHarvester(new TurnCandidateHarvester(serverAddr));\n            System.out.printf(\"Agent state: %s\\n\", agent.getState());\n            // add a stream\n            IceMediaStream stream = agent.getStream(\"junit\");\n            assertNull(stream);\n            stream = agent.createMediaStream(\"junit\");\n            assertNotNull(stream);\n            // create a data component\n            Component rtp = null;\n            try\n            {\n                rtp =\n                    agent.createComponent(stream, Transport.UDP, 7000, 7000,\n                                    7016);\n            }\n            catch (Exception e)\n            {\n                e.printStackTrace();\n            }\n            for (CandidateHarvester harvester : agent.getHarvesters())\n            {\n                System.out.printf(\"Harvesting for rtp via %s\\n\", harvester);\n                try\n                {\n                    Collection<LocalCandidate> candidates =\n                        harvester.harvest(rtp);\n                    if (candidates.isEmpty())\n                    {\n                        System.out.println(\"No candidates found\");\n                        continue;\n                    }\n                    System.out.printf(\"Harvested candidates: %s\\n\", candidates);\n                    for (LocalCandidate candidate : candidates)\n                    {\n                        rtp.addLocalCandidate(candidate);\n                    }\n                    break;\n                }\n                catch (Exception e)\n                {\n                    e.printStackTrace();\n                }\n            }\n            // start connection establishment\n            agent.startConnectivityEstablishment();\n            IceProcessingState state;\n            while ((state = agent.getState()) != IceProcessingState.TERMINATED)\n            {\n                System.out.printf(\n                                \"Endpoint connectivity establishment in process, state: %s\\n\",\n                                state);\n                try\n                {\n                    if (state == IceProcessingState.FAILED) { throw new Exception(\n                                    \"ICE connectivity failed\"); }\n                    // sleep until ICE terminates or fails\n                    Thread.sleep(500);\n                }\n                catch (Exception e)\n                {\n                    e.printStackTrace();\n                    agent.free();\n                    break;\n                }\n            }\n            // get candidates\n            CandidatePair rtpPair =\n                agent.getStream(\"junit\").getComponent(Component.RTP)\n                                .getSelectedPair();\n            System.out.printf(\"Endpoint IP: %s\\n\", rtpPair.getRemoteCandidate()\n                            .getTransportAddress());\n            IceUdpSocketWrapper wrapper =\n                new IceUdpSocketWrapper(rtpPair.getDatagramSocket());\n            // wrapper.receive(packet);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/test/java/org/jitsi/turnserver/stack/TurnServerTestSuite.java",
    "content": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org).\n *\n * Copyright @ 2015 Atlassian Pty Ltd\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\npackage org.jitsi.turnserver.stack;\n\nimport org.jitsi.turnserver.client.*;\nimport org.junit.runner.*;\nimport org.junit.runners.*;\n\n/**\n * Contains the suite of tests in the turnserver project.\n *\n * @author Paul Gregoire\n */\n@RunWith(Suite.class)\n@Suite.SuiteClasses({\n    ClientTest.class\n})\npublic class TurnServerTestSuite\n{\n}\n"
  },
  {
    "path": "src/test/resources/TurnServer.propertes",
    "content": "org.jitsi.turnserver.udp_port = 3478;\norg.jitsi.turnserver.max_port = 65535;\norg.jitsi.turnserver.min_port = 49152;\norg.jitsi.turnserver.unpriv_user = ;\norg.jitsi.turnserver.max_client = ;\norg.jitsi.turnserver.max_relay_per_username = ;\norg.jitsi.turnserver.allocation_lifetime = ;\norg.jitsi.turnserver.nonce_key = 79897BC1042DF24AAE2FACFF9E2A6093;\norg.jitsi.turnserver.ca_file = ;\norg.jitsi.turnserver.cert_file = ;\norg.jitsi.turnserver.private_key_file = ;\norg.jitsi.turnserver.realm = ;\norg.jitsi.turnserver.bandwidth_per_allocation = ;\norg.jitsi.turnserver.restricted_bandwidth = ;\norg.jitsi.turnserver.account_method = ;\norg.jitsi.turnserver.account_file = ;\n\n"
  },
  {
    "path": "src/test/resources/accounts.txt",
    "content": "JitsiGsocStudent:8156CE4E8499609C34C641E2C2904171\nJitsiGsocMentor:654714090BC4348274203EE55EEFBB26\n\n"
  },
  {
    "path": "src/test/resources/logging.properties",
    "content": "############################################################\n#  Default Logging Configuration File\n#\n# You can use a different file by specifying a filename\n# with the java.util.logging.config.file system property.\n# For example java -Djava.util.logging.config.file=myfile\n############################################################\n\n############################################################\n#  Global properties\n############################################################\n\n# \"handlers\" specifies a comma separated list of log Handler\n# classes.  These handlers will be installed during VM startup.\n# Note that these classes must be on the system classpath.\n# By default we only configure a ConsoleHandler, which will only\n# show messages at the INFO and above levels.\nhandlers= java.util.logging.ConsoleHandler\n\n# To also add the FileHandler, use the following line instead.\n#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler\n\n# Default global logging level.\n# This specifies which kinds of events are logged across\n# all loggers.  For any given facility this global level\n# can be overriden by a facility specific level\n# Note that the ConsoleHandler also has a separate level\n# setting to limit messages printed to the console.\n.level= ALL\n\n############################################################\n# Handler specific properties.\n# Describes specific configuration info for Handlers.\n############################################################\n\n# default file output is in user's home directory.\n\n# Note that the level for the console handler may be modified by the application.\n# Also note that you won't see any logs with a Level Lower than this one.\njava.util.logging.ConsoleHandler.level = ALL\njava.util.logging.ConsoleHandler.formatter = org.ice4j.util.Ice4jLogFormatter\n\n\n############################################################\n# Facility specific properties.\n# Provides extra control for each logger.\n############################################################\n\n# Things coming from ice4j\norg.ice4j.level = FINEST\ntest.level = FINEST\n\n"
  }
]