Full Code of jitsi/turnserver for AI

master 3f4cbd6bfa43 cached
54 files
288.1 KB
61.9k tokens
310 symbols
1 requests
Download .txt
Showing preview only (308K chars total). Download the full file or copy to clipboard to get everything.
Repository: jitsi/turnserver
Branch: master
Commit: 3f4cbd6bfa43
Files: 54
Total size: 288.1 KB

Directory structure:
gitextract_bn5f4f2j/

├── .gitignore
├── LICENSE
├── README.md
├── build.xml
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── org/
    │   │       └── jitsi/
    │   │           └── turnserver/
    │   │               ├── IndicationListener.java
    │   │               ├── TurnException.java
    │   │               ├── TurnStackProperties.java
    │   │               ├── collectors/
    │   │               │   ├── AllocationResponseCollector.java
    │   │               │   ├── ChannelBindResponseCollector.java
    │   │               │   ├── ConnectResponseCollector.java
    │   │               │   ├── ConnectionBindResponseCollector.java
    │   │               │   ├── CreatePermissionResponseCollector.java
    │   │               │   └── RefreshResponseCollector.java
    │   │               ├── listeners/
    │   │               │   ├── AllocationRequestListener.java
    │   │               │   ├── BindingRequestListener.java
    │   │               │   ├── ChannelBindRequestListener.java
    │   │               │   ├── ConnectRequestListener.java
    │   │               │   ├── ConnectionAttemptIndicationListener.java
    │   │               │   ├── ConnectionBindRequestListener.java
    │   │               │   ├── CreatePermissionRequestListener.java
    │   │               │   ├── DataIndicationListener.java
    │   │               │   ├── PeerTcpConnectEventListner.java
    │   │               │   ├── RefreshRequestListener.java
    │   │               │   └── SendIndicationListener.java
    │   │               ├── socket/
    │   │               │   ├── IceTcpEventizedServerSockerWrapper.java
    │   │               │   ├── TcpConnectEvent.java
    │   │               │   ├── TcpConnectEventGenerator.java
    │   │               │   └── TcpConnectEventListener.java
    │   │               ├── stack/
    │   │               │   ├── Allocation.java
    │   │               │   ├── ChannelBind.java
    │   │               │   ├── FiveTuple.java
    │   │               │   ├── Permission.java
    │   │               │   ├── ServerChannelDataEventHandler.java
    │   │               │   ├── ServerPeerUdpEventHandler.java
    │   │               │   ├── TurnClientTransaction.java
    │   │               │   ├── TurnServer.java
    │   │               │   ├── TurnServerTransaction.java
    │   │               │   └── TurnStack.java
    │   │               └── turnClient/
    │   │                   ├── ClientChannelDataEventHandler.java
    │   │                   ├── InteractiveUdpPeer.java
    │   │                   ├── StunClient.java
    │   │                   ├── TcpPeer.java
    │   │                   ├── TurnAllocationClient.java
    │   │                   ├── TurnClient.java
    │   │                   └── TurnTcpAllocationClient.java
    │   └── resources/
    │       ├── TurnServer.propertes
    │       ├── accounts.txt
    │       └── logging.properties
    └── test/
        ├── java/
        │   └── org/
        │       └── jitsi/
        │           └── turnserver/
        │               ├── client/
        │               │   └── ClientTest.java
        │               └── stack/
        │                   └── TurnServerTestSuite.java
        └── resources/
            ├── TurnServer.propertes
            ├── accounts.txt
            └── logging.properties

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.idea
bin
.project
.classpath
.settings
target/


================================================
FILE: LICENSE
================================================

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
turnserver
==========

Welcome to the TurnServer project - open-source TURN server implementation.

The 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.

The 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).

TurnServer is freely available under the terms of the Apache Public License 2.0.


================================================
FILE: build.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>

<project name="turnserver" basedir="." default="rebuild">
	<property name="dest" value="classes"/>
    <property name="dest-test" value="classes-test"/>
	<property name="lib" value="lib"/>
	<property name="src" value="src"/>
	<property name="test" value="test"/>
    <property name="cmd.args" value="0.0.0.0 3487"/>
	<property name="turnserver.jar" value="turnserver.jar"/>
	<property name="doc" value="doc"/>
	<property name="java.doc" value="${doc}/api"/>

	<path id="project.class.path">
		<pathelement location="${dest}"/>
		<pathelement location="${lib}/jain-sdp.jar"/>
		<pathelement location="${lib}/weupnp-0.1.2-SNAPSHOT.jar"/>
		<pathelement location="${lib}/ice4j.jar"/>
<!--		<pathelement location="G:\\myPoject\ice4jProj\ice4j-read-only\\ice4j.jar"/>  -->
	</path>
    <path id="test.class.path">
        <path refid="project.class.path" />
        <pathelement location="${dest-test}"/>
    </path>

	<!--Patternset to exclude files from the output directory:-->
	<patternset id="dest.exclude">
		<exclude name="package cache/"/>
		<exclude name="dependency cache/"/>
	</patternset>

	<!--  ANT TARGETS -->

	<!-- compiles all classes -->
	<target name="compile" depends="init">
		<javac classpathref="project.class.path"
               debug="true"
               deprecation="true"
               destdir="${dest}"
               nowarn="false"
               optimize="true"
               target="1.5"
               source="1.5"
               includeantruntime="false">
			<src path="${src}"/>
			<compilerarg value="-Xlint"/>
		</javac>
	</target>
	
	<!-- compiles all tests -->
	    <target name="compile-tests" depends="init">
	        <javac classpathref="test.class.path"
	               debug="true"
	               deprecation="true"
	               destdir="${dest-test}"
	               nowarn="false"
	               optimize="true"
	               target="1.5"
	               source="1.5">
	            <src path="${test}"/>
	            <compilerarg value="-Xlint"/>
	        </javac>
	    </target>

	<!-- copies ressource files if any to the classes directory -->
	<target name="resource">
		<copy todir="${dest}">
			<fileset dir="${src}">
				<include name="**/*.jpe"/>
				<include name="**/*.jpeg"/>
				<include name="**/*.rmf"/>
				<include name="**/*.wav"/>
				<include name="**/*.mid"/>
				<include name="**/*.midi"/>
				<include name="**/*.au"/>
				<include name="**/*.gif"/>
				<include name="**/*.png"/>
				<include name="**/*.jpg"/>
				<include name="**/*.aiff"/>
				<include name="**/*.properties"/>
			</fileset>
		</copy>
	</target>

	<!-- creates the javadocs -->
	<target name="javadoc">
		<javadoc author="true" destdir="${java.doc}" package="true">
			<fileset dir="${src}"/>
		</javadoc>
	</target>

	<!-- delete the contents of the classes directory-->
	<target name="clean">
		<delete failonerror="false" includeemptydirs="true">
			<fileset dir="${dest}"/>
            <fileset dir="${dest-test}"/>
			<fileset dir="doc" />
		</delete>
		<delete file="${turnserver.jar}" failonerror="true" quiet="false"/>
	</target>

	<!-- make everything -->
	<target name="make" depends="compile,resource,jar"/>

	<!-- clean and make everything -->
	<target name="rebuild" depends="clean,make" />

	<!-- make javadoc -->
	<target name="doc" depends="make,javadoc" />

	<!-- create needed subdirs-->
	<target name="init">
		<mkdir dir="${dest}"/>
        <mkdir dir="${dest-test}"/>
	</target>

	<!-- create jar file-->
	<target name="jar" depends="compile">
		<jar compress="true" destfile="${turnserver.jar}">
			<fileset dir="${dest}">
				<patternset refid="dest.exclude"/>
				<include name="**/*.*"/>
			</fileset>
		</jar>
	</target>

	<!-- runs our Turn Server -->
	<target name="turn-server" depends="rebuild">
		<java fork="true"
			classname="org.jitsi.turnserver.stack.TurnServer"
		    classpathref="project.class.path">
            <arg line="cmd.args" />
			<!-- Tell java.util.logging about our logging preferences -->
			<sysproperty key="java.util.logging.config.file"
		                         value="lib/logging.properties"/>
    	</java>
	</target>

	<!-- runs our Turn Client -->
	<target name="turn-udp-client">
		<java fork="true"
			classname="org.jitsi.turnserver.turnClient.TurnAllocationClient"
			classpathref="project.class.path">

			<!-- Tell java.util.logging about our logging preferences -->
			<sysproperty key="java.util.logging.config.file"
						 value="lib/logging.properties"/>
		</java>
	</target>
	
	<!-- runs our Turn Tcp Client -->
	<target name="turn-tcp-client">
		<java fork="true"
			classname="org.jitsi.turnserver.turnClient.TurnTcpAllocationClient"
			classpathref="project.class.path">

			<!-- Tell java.util.logging about our logging preferences -->
			<sysproperty key="java.util.logging.config.file"
						 value="lib/logging.properties"/>
		</java>
	</target>
	
	<!-- runs our Turn Tcp Peer -->
	<target name="turn-tcp-peer">
		<java fork="true"
			classname="org.jitsi.turnserver.turnClient.TcpPeer"
			classpathref="project.class.path">

			<!-- Tell java.util.logging about our logging preferences -->
			<sysproperty key="java.util.logging.config.file"
						 value="lib/logging.properties"/>
		</java>
	</target>
	
	<!-- runs our ICE test class -->
		<target name="test-ice">
			<java fork="true"
				classname="test.Ice"
			    classpathref="test.class.path">
	            <!-- Tell java.util.logging about our logging preferences -->
				<sysproperty key="java.util.logging.config.file"
			                         value="lib/logging.properties"/>
	    	</java>
		</target>

</project>


================================================
FILE: pom.xml
================================================
<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.jitsi</groupId>
    <artifactId>jitsi-universe</artifactId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>../jitsi-universe/pom.xml</relativePath>
  </parent>

  <artifactId>turnserver</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>turnserver</name>
  <url>https://github.com/jitsi/turnserver</url>

  <dependencies>
    <dependency>
      <groupId>org.jitsi</groupId>
      <artifactId>ice4j</artifactId>
    </dependency>
    <dependency>
      <groupId>javax.sdp</groupId>
      <artifactId>jain-sdp</artifactId>
    </dependency>
    <dependency>
      <groupId>org.bitlet</groupId>
      <artifactId>weupnp</artifactId>
    </dependency>
    <!-- test -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <includes>
            <include>**/*TestSuite.*</include>
          </includes>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <repository>
      <id>jitsi-maven-repository-releases</id>
      <layout>default</layout>
      <name>Jitsi Maven Repository (Releases)</name>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <url>https://github.com/jitsi/jitsi-maven-repository/raw/master/releases/</url>
    </repository>
    <repository>
      <id>jitsi-maven-repository-snapshots</id>
      <layout>default</layout>
      <name>Jitsi Maven Repository (Snapshots)</name>
      <releases>
        <enabled>false</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
      <url>https://github.com/jitsi/jitsi-maven-repository/raw/master/snapshots/</url>
    </repository>
  </repositories>
</project>


================================================
FILE: src/main/java/org/jitsi/turnserver/IndicationListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver;

import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

import org.jitsi.turnserver.stack.*;

/**
 * Abstract class for Indication Listener.
 * 
 * @author Aakash Garg
 */
public abstract class IndicationListener implements MessageEventHandler 
{
    /**
     * The turnStack for this instance.
     */
    private final TurnStack turnStack;
    
    /**
     * Represents if the listener is started or not.
     */
    private boolean started = false;
    
    /**
     * Represents the localAddress associated with the listener.
     */
    private TransportAddress localAddress;

    /**
     * The turnStack to call.
     * @param turnStack
     */
    public IndicationListener(TurnStack turnStack)
    {
	this.turnStack = turnStack;
    }
    
    /**
     * Checks if the message is an Indication message. If yes it then finds the
     * five tuple and corresponding allocation and calls the handleIndication.
     */
    @Override
    public void handleMessageEvent(StunMessageEvent evt) {
	Message message = evt.getMessage();
	if(Message.isIndicationType(message.getMessageType()))
	{
	    Indication ind = (Indication) message;
	    
	    TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = serverAddress.getTransport();
            FiveTuple fiveTuple =
                new FiveTuple(clientAddress, serverAddress, transport);
            Allocation alloc = turnStack.getServerAllocation(fiveTuple);
            
	    this.handleIndication(ind,alloc);
	}		
    }
    
    /**
     * Sets the turnStack for this class.
     * @return
     */
    public TurnStack getTurnStack()
    {
	return this.turnStack;
    }
    
    /**
     * Sets the localAddress.
     * 
     * @param localAddress
     *            the localAddress to listen on.
     */
    public void setLocalAddress(TransportAddress localAddress)
    {
	this.localAddress = localAddress;
    }
    
    /**
     * Handles the Indication message.
     * It must be implemented by the subclass.
     * 
     * @param ind
     *            the Indication to handle.
     * @param alloc
     *            the corresponding to the request.
     */
    abstract public void handleIndication(Indication ind, Allocation alloc);

    /**
     * Starts this <tt>IndicationListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addIndicationListener(localAddress, this);
            started = true;
        }
    }

    /**
     * Stops this <tt>IndicationListenerr</tt>. A stopped
     * <tt>IndicationListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeIndicationListener(localAddress, this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/TurnException.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver;

import org.ice4j.StunException;

/**
 * @author Aakash Garg
 * 
 */
public class TurnException
    extends StunException
{

    /**
     * 
     */
    private static final long serialVersionUID = -8004612606830162094L;

    /**
     * 
     */
    public TurnException()
    {
    }

    /**
     * @param id
     */
    public TurnException(int id)
    {
        super(id);
    }

    /**
     * @param message
     */
    public TurnException(String message)
    {
        super(message);
    }

    /**
     * @param id
     * @param message
     */
    public TurnException(int id, String message)
    {
        super(id, message);
    }

    /**
     * @param id
     * @param message
     * @param cause
     */
    public TurnException(int id, String message, Throwable cause)
    {
        super(id, message, cause);
    }

    /**
     * @param message
     * @param cause
     */
    public TurnException(String message, Throwable cause)
    {
        super(message, cause);
    }

    /**
     * @param cause
     */
    public TurnException(Throwable cause)
    {
        super(cause);
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/TurnStackProperties.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver;

import java.util.logging.*;

import org.ice4j.*;

/**
 * The class contains a number of property names and their default values that
 * we use to configure the behavior of the Turnserver stack.
 *
 * @author Aakash Garg.
 */
public class TurnStackProperties extends StackProperties
{
    /**
     * Our class logger.
     */
    private static final Logger logger
        = Logger.getLogger(TurnStackProperties.class.getName());

    public static final String TURNSERVER_UDP_PORT 
    	= "org.jitsi.turnserver.udp_port";

    public static final int DEFAULT_TURNSERVER_UDP_PORT = 3478;

    public static final String TURNSERVER_MIN_PORT 
	= "org.jitsi.turnserver.min_port";

    public static final int DEFAULT_TURNSERVER_MIN_PORT = 49152;

    public static final String TURNSERVER_MAX_PORT 
	= "org.jitsi.turnserver.max_port";

    public static final int DEFAULT_TURNSERVER_MAX_PORT = 65535;

    public static final String ALLOCATION_LIFETIME 
	= "org.jitsi.turnserver.allocation_lifetime";

    public static final int DEFAULT_ALLOCATION_LIFETIME = 10 * 60 * 1000;
    
    public static final String MAX_ALLOCATIONS 
	= "org.jitsi.turnserver.max_allocations";

    public static final int DEFAULT_MAX_ALLOCATIONS = 50;
    
    public static final String CHANNELBIND_LIFETIME 
	= "org.jitsi.turnserver.channelbind_lifetime";

    public static final int DEFAULT_CHANNELBIND_LIFETIME = 10 * 60 * 1000;

    public static final String MAX_PERMISSIONS_PER_ALLOCATION 
	= "org.jitsi.turnserver.max_permissions_per_allocation";

    public static final int DEFAULT_MAX_PERMISSIONS_PER_ALLOCATION = 10;

    public static final String PERMISSION_LIFETIME 
	= "org.jitsi.turnserver.permission_lifetime";

    public static final int DEFAULT_PERMISSION_LIFETIME = 300 * 1000;
    
    public static final String MAX_CHANNELBINDS_PER_ALLOCATION 
	= "org.jitsi.turnserver.max_channelbinds_per_allocation";

    public static final int DEFAULT_MAX_CHANNELBINDS_PER_ALLOCATION = 10;

    public static final String REALM 
	= "org.jitsi.turnserver.realm";
   
    public static final String DEFAULT_REALM 
 	= "org.jitsi.turnserver";
    
    public static final String DEFAULT_ACCOUNTS_FILE
    	= "";
    
    public static final String ACCOUNTS_FILE
    	= "";

    
}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/AllocationResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.io.IOException;
import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
import org.jitsi.turnserver.stack.TurnStack;

/**
 * The class that would be handling to incoming Allocation responses.
 * 
 * @author Aakash Garg
 */
public class AllocationResponseCollector
    implements ResponseCollector
{
    /**
     * The <tt>Logger</tt> used by the <tt>AllocationresponseCollector</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(AllocationResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new AllocationresponseCollector
     * 
     * @param turnStack
     */
    public AllocationResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)
        {
            ErrorCodeAttribute errorCodeAttribute =
                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);
            NonceAttribute nonceAttr = (NonceAttribute) message
		    .getAttribute(Attribute.NONCE);
//	    System.out.println("Nonce : "+new Nonce(nonceAttr.getNonce()));
            Request request = MessageFactory.createAllocateRequest();
            TransactionID tran = TransactionID.createNewTransactionID();
            try {
		request.setTransactionID(tran.getBytes());
	    } catch (StunException e1) {
		System.err.println("Unable to set tran ID.");
	    }
            request.putAttribute(nonceAttr);
            String username = "JitsiGsocStudent";
	    UsernameAttribute usernameAttr = AttributeFactory
		    .createUsernameAttribute(username+":");
/*	    
	    byte[] key = this.stunStack.getCredentialsManager().getLocalKey(
		    username);
	    System.out.println("Username found "
		    + (this.stunStack.getCredentialsManager()
			    .checkLocalUserName(username)));
	    System.out.println("User "
		    + username
		    + " found : "
		    + TurnStack.toHexString(key));
	    
	    byte[] messageB = request.encode(stunStack);
*/	    MessageIntegrityAttribute msgInt = AttributeFactory
		    .createMessageIntegrityAttribute(username);
	    RequestedTransportAttribute reqTrans = AttributeFactory
		    .createRequestedTransportAttribute(
			    RequestedTransportAttribute.UDP);
	    try{
//		    msgInt.encode(stunStack, messageB, 0, messageB.length);		
	    }catch(Exception e)
	    {
		e.printStackTrace();
	    }
	    request.putAttribute(reqTrans);
	    request.putAttribute(usernameAttr);
	    request.putAttribute(msgInt);
	    try {
		this.stunStack.sendRequest(request, evt.getRemoteAddress(),
		    evt.getLocalAddress(), this);
	    }
	    catch (Exception e) {
		e.printStackTrace();
//		System.err.println(e.getMessage());
	    }
            if(errorCodeAttribute != null)
            {
		System.out.println("Error Code : "
			+ (int) errorCodeAttribute.getErrorCode());
            }
            switch (errorCodeAttribute.getErrorCode())
            {
            case ErrorCodeAttribute.BAD_REQUEST:
                // code for bad response error
                break;
            case ErrorCodeAttribute.UNAUTHORIZED:
                // code for unauthorised error code
                break;
            case ErrorCodeAttribute.FORBIDDEN:
                // code for forbidden error code
                break;
            case ErrorCodeAttribute.UNKNOWN_ATTRIBUTE:
                // code for Unknown Attribute error code
                break;
            case ErrorCodeAttribute.ALLOCATION_MISMATCH:
                // code for Allocation mismatch Error
                break;
            case ErrorCodeAttribute.STALE_NONCE:
                // code for Stale Nonce error code
                break;
            case ErrorCodeAttribute.WRONG_CREDENTIALS:
                // code for wrong credentials error code
                break;
            case ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL:
                // code for unsupported transport protocol
                break;
            case ErrorCodeAttribute.ALLOCATION_QUOTA_REACHED:
                // code for allocation quota reached
                break;
            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:
                // code for insufficient capacity
                break;
                
            }
        }
        else if (message.getMessageType() == Message.ALLOCATE_RESPONSE)
        {
            System.out.println("Allocate Sucess Response.");
            // code for doing processing of Allocation success response
        }
        else
        {
            return;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/ChannelBindResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming ChannelBind
 * response.
 * 
 * @author Aakash Garg
 */
public class ChannelBindResponseCollector
    implements ResponseCollector
{

    /**
     * The <tt>Logger</tt> used by the <tt>ChannelBindresponseCollector</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ChannelBindResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new ChannelBindresponseCollector
     * 
     * @param turnStack
     */
    public ChannelBindResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CHANNELBIND_ERROR_RESPONSE)
        {
            ErrorCodeAttribute errorCodeAttribute =
                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);
            switch (errorCodeAttribute.getErrorCode())
            {
            case ErrorCodeAttribute.BAD_REQUEST:
                // code for bad response error
                break;
            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:
                // logic for processing insufficient capacity error code
                break;
            }
        }
        else if (message.getMessageType() == Message.CHANNELBIND_RESPONSE)
        {
            // logic for processing the success response.
        }
        else
        {
            return;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {
        // TODO Auto-generated method stub

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/ConnectResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming Connect response.
 * 
 * @author Aakash Garg
 */
public class ConnectResponseCollector
    implements ResponseCollector
{

    /**
     * The <tt>Logger</tt> used by the <tt>ConnectresponseCollector</tt> class
     * and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ConnectResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new ConnectresponseCollector
     * 
     * @param turnStack
     */
    public ConnectResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CONNECT_ERROR_RESPONSE)
        {
            ErrorCodeAttribute errorCodeAttribute =
                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);
            switch (errorCodeAttribute.getErrorCode())
            {
            case ErrorCodeAttribute.ALLOCATION_MISMATCH:
                // code for bad response error
                break;
            case ErrorCodeAttribute.CONNECTION_ALREADY_EXISTS:
                // code for processing connection already exists error
                break;
            case ErrorCodeAttribute.FORBIDDEN:
                // code for processing forbidden error code
                break;
            case ErrorCodeAttribute.CONNECTION_TIMEOUT_OR_FAILURE:
                // code for processing connection timeout or failure error code.
                break;
            }
        }
        else if (message.getMessageType() == Message.CONNECT_RESPONSE)
        {
            // code for doing processing of Connect success response
        }
        else
        {
            return;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {
        // TODO Auto-generated method stub

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/ConnectionBindResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming ConnectionBind
 * response.
 * 
 * @author Aakash Garg
 */
public class ConnectionBindResponseCollector
    implements ResponseCollector
{

    /**
     * The <tt>Logger</tt> used by the <tt>ConnectionBindresponseCollector</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ConnectionBindResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new ConnectionBindresponseCollector
     * 
     * @param turnStack
     */
    public ConnectionBindResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)
        {
            ErrorCodeAttribute errorCodeAttribute =
                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);
            switch (errorCodeAttribute.getErrorCode())
            {
            case ErrorCodeAttribute.BAD_REQUEST:
                // code for bad response error
                break;
            }
        }
        else if (message.getMessageType() == Message.ALLOCATE_RESPONSE)
        {
            // code for doing processing of ConnectionBind success response
        }
        else
        {
            return;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {
        // TODO Auto-generated method stub

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/CreatePermissionResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming CreatePermission
 * response.
 * 
 * @author Aakash Garg
 */
public class CreatePermissionResponseCollector
    implements ResponseCollector
{
    /**
     * The <tt>Logger</tt> used by the
     * <tt>CreatePermissionResponseCollector</tt> class and its instances for
     * logging output.
     */
    private static final Logger logger = Logger
        .getLogger(CreatePermissionResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new CreatePermissionResponseCollector
     * 
     * @param turnStack
     */
    public CreatePermissionResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.ALLOCATE_ERROR_RESPONSE)
        {
            ErrorCodeAttribute errorCodeAttribute =
                (ErrorCodeAttribute) message.getAttribute(Attribute.ERROR_CODE);
            switch (errorCodeAttribute.getErrorCode())
            {
            case ErrorCodeAttribute.BAD_REQUEST:
                // logic for processing bad request error
                break;
            case ErrorCodeAttribute.INSUFFICIENT_CAPACITY:
                // logic for processing insufficient capacity error
                break;
            case ErrorCodeAttribute.FORBIDDEN:
                // logic for processing forbidden error code
                break;
            default:
                logger.finer("error : Received error response with error code "
                    + errorCodeAttribute.getErrorCode() + evt);
            }
        }
        else
        {
            return;
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {
        // TODO Auto-generated method stub

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/collectors/RefreshResponseCollector.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.collectors;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming Refresh
 * responses.
 * 
 * @author Aakash Garg
 */
public class RefreshResponseCollector
    implements ResponseCollector
{
    /**
     * The <tt>Logger</tt> used by the <tt>RefreshresponseCollector</tt> class
     * and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(RefreshResponseCollector.class.getName());

    private final StunStack stunStack;

    /**
     * Creates a new RefreshResponseCollector
     * 
     * @param turnStack
     */
    public RefreshResponseCollector(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processResponse(org.ice4j.StunResponseEvent)
     */
    @Override
    public void processResponse(StunResponseEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.finer("Received response " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.REFRESH_ERROR_RESPONSE)
        {
            // delete allocation
        }
        else if (message.getMessageType() == Message.REFRESH_RESPONSE)
        {
            // update allocation
        }
        else
        {
            return;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.ResponseCollector#processTimeout(org.ice4j.StunTimeoutEvent)
     */
    @Override
    public void processTimeout(StunTimeoutEvent event)
    {

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/AllocationRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
import org.jitsi.turnserver.stack.*;

/**
 * The class that would be handling and responding to incoming Allocation
 * requests that are Allocation and sends a success or error response.
 * 
 * @author Aakash Garg
 */
public class AllocationRequestListener
    implements RequestListener
{
    /**
     * The <tt>Logger</tt> used by the <tt>AllocationRequestListener</tt> class
     * and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(AllocationRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>AllocationrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new AllocationRequestListener
     * 
     * @param turnStack
     */
    public AllocationRequestListener(StunStack stunStack)
    {
        if (stunStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) stunStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.ALLOCATE_REQUEST)
        {
	    logger.finest("Received a Allocation Request from "
		    + evt.getRemoteAddress());
           
            Response response = null;
            RequestedTransportAttribute requestedTransportAttribute =
                (RequestedTransportAttribute) message
                    .getAttribute(Attribute.REQUESTED_TRANSPORT);

            DontFragmentAttribute dontFragmentAttribute =
                (DontFragmentAttribute) message
                    .getAttribute(Attribute.DONT_FRAGMENT);

            ReservationTokenAttribute reservationTokenAttribute =
                (ReservationTokenAttribute) message
                    .getAttribute(Attribute.RESERVATION_TOKEN);

            LifetimeAttribute lifetimeAttribute = 
                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);
            
            EvenPortAttribute evenPort = 
                (EvenPortAttribute) message.getAttribute(Attribute.EVEN_PORT);
            
            if (lifetimeAttribute == null)
            {
                lifetimeAttribute =
                    AttributeFactory
                        .createLifetimeAttribute(
                            (int) (Allocation.DEFAULT_LIFETIME / 1000));
            }
            
            EvenPortAttribute evenPortAttribute =
                (EvenPortAttribute) message.getAttribute(Attribute.EVEN_PORT);
            
            TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = serverAddress.getTransport();
            FiveTuple fiveTuple =
                new FiveTuple(clientAddress, serverAddress, transport);
              
            Character errorCode = null;
            if(!this.turnStack.canHaveMoreAllocations())
            {
                errorCode = ErrorCodeAttribute.ALLOCATION_QUOTA_REACHED;
            }
            else if (requestedTransportAttribute == null)
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else if (requestedTransportAttribute.getRequestedTransport() 
                == RequestedTransportAttribute.TCP)
            {
                if (!this.turnStack.isTCPAllowed())
                    errorCode =
                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;
                else if (reservationTokenAttribute != null)
                {
                    logger.finest("error : reservation token found in TCP message.");
                    errorCode =
                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;
                }
                else if (evenPort != null)
                {
                    logger.finest("error : even port found in TCP message.");
                    errorCode =
                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;
                }
                else if (dontFragmentAttribute != null)
                {
                    logger.finest("error : dont fragment found in TCP message.");
                    errorCode =
                        ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;
                }
            }
            else if (requestedTransportAttribute.getRequestedTransport() 
                == RequestedTransportAttribute.UDP 
                && !this.turnStack.isUDPAllowed())
            {
                errorCode = ErrorCodeAttribute.UNSUPPORTED_TRANSPORT_PROTOCOL;
                logger.finest("UDP not alllowed on Allocation Requests.");
            }
            else if (reservationTokenAttribute != null
                && evenPortAttribute != null)
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
                logger
                    .finest("Both reservation Token and Even PortAttribute are found in Allocation request.");
            }
            
            if (turnStack.getServerAllocation(fiveTuple)!=null)
            {
                errorCode = ErrorCodeAttribute.ALLOCATION_MISMATCH; 
                logger.finest("Allocation not found for the "+fiveTuple);
            }
            // do other checks here
            
            if (errorCode == null)
            {
                if(evenPortAttribute==null)
                {
                    evenPortAttribute =
                        AttributeFactory.createEvenPortAttribute(false);
                }
                TransportAddress relayAddress = turnStack.getNewRelayAddress(
                    evenPortAttribute.isRFlag(), serverAddress.getTransport());
/*                logger.finest("Added a new Relay Address "+relayAddress);
                System.out.println("Added a new Relay Address "+relayAddress
                	+" for client "+evt.getRemoteAddress());
*/              
                Allocation allocation = null;
                synchronized(this)
                {
                    allocation =
                        new Allocation(relayAddress, fiveTuple,
                            lifetimeAttribute.getLifetime());
                    this.turnStack.addNewServerAllocation(allocation);
//                    System.out.println("Added a new allocation.");
                }
                logger.finest("Added a new Allocation with relay address :"
				+ allocation.getRelayAddress()+" for client "
				+evt.getRemoteAddress());
                
                response = MessageFactory.createAllocationResponse(
                     (Request) message,
                     allocation.getFiveTuple().getClientTransportAddress(), 
                     allocation.getRelayAddress(), 
                     (int) allocation.getLifetime());
                
                XorRelayedAddressAttribute relayedXorAddress 
                    = AttributeFactory.createXorRelayedAddressAttribute(
                            allocation.getRelayAddress(),
                            evt.getTransactionID().getBytes());
                response.putAttribute(relayedXorAddress);
                
                LifetimeAttribute lifetime 
                    = AttributeFactory.createLifetimeAttribute(
                        (int)(allocation.getLifetime()));
                response.putAttribute(lifetime);
                
                XorMappedAddressAttribute clientXorAddress 
                    = AttributeFactory.createXorMappedAddressAttribute(
                        clientAddress,
                        evt.getTransactionID().getBytes());
               response.putAttribute(clientXorAddress);
                
                if(evenPort!=null)
                {
                    // TODO : logic for process and creating Reservation Token.
                    byte[] token = {7,7,7,7};
                    ReservationTokenAttribute reservationToken
                        = AttributeFactory.createReservationTokenAttribute(
                            token);
                    response.putAttribute(reservationToken);
                    if(evenPort.isRFlag())
                    {
                        TransportAddress relayAddess
                            = allocation.getRelayAddress();
                        TransportAddress nextAddress 
                            = new TransportAddress(
                                relayAddress.getAddress(),
                                relayAddress.getPort()+1,
                                relayAddress.getTransport());
                        boolean isReserved
                            = this.turnStack.reservePort(nextAddress);
                        if(isReserved)
                        {
                            logger.log(
                                Level.FINEST,
                                nextAddress+" reserved by "+fiveTuple);
                        }
                        else
                        {
                            logger.log(
                                Level.FINEST,
                                nextAddress+" not reserved by "+fiveTuple);
                        }
                    }
                }               
            }
            else
            {
                System.err.println("Error Code " + (int)errorCode
                        + " on Allocation Request");
                logger.finest("Error Code " + (int)errorCode
                    + " on Allocation Request");
                response =
                    MessageFactory.createAllocationErrorResponse(errorCode);
            }
            
            try
            {
                logger
                    .fine("Trying to send response to "
                        + evt.getRemoteAddress() + " from "
                        + evt.getLocalAddress());
                turnStack.sendResponse(
                    evt.getTransactionID().getBytes(), response,
                    evt.getLocalAddress(), evt.getRemoteAddress());
                logger.finest("Response sent.");
            }
            catch (Exception e)
            {
        	System.err.println("Failed to send response");
                logger.log(
                    Level.INFO, "Failed to send " + response + " through "
                        + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
        else
        {
            return;
        }
    }

    /**
     * Starts this <tt>AllocationRequestListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>AllocationRequestListenerr</tt>. A stopped
     * <tt>AllocationRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/BindingRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jitsi.turnserver.listeners;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * The class that would be handling and responding to incoming requests that are
 * validated and sends a SUCCESS response
 * 
 * @author Aakash Garg
 */
public class BindingRequestListener
    implements RequestListener
{
    /**
     * The <tt>Logger</tt> used by the <tt>BindingRequestListener</tt> class and
     * its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(BindingRequestListener.class.getName());

    private final StunStack stunStack;

    /**
     * The indicator which determines whether this
     * <tt>ValidatedrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new BindingRequestListener
     * 
     * @param turnStack
     */
    public BindingRequestListener(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
        }
        Message message = evt.getMessage();

        if (message.getMessageType() == Message.BINDING_REQUEST)
        {
            logger.finest("Received a Binding Request from "
                + evt.getRemoteAddress());
            TransportAddress mappedAddress = evt.getRemoteAddress();
            // Response response =
            // MessageFactory.createBindingResponse(request,mappedAddress);
            TransportAddress sourceAddress = evt.getLocalAddress();
            TransportAddress changedAddress =
                new TransportAddress("stunserver.org", 3489, Transport.UDP);
            Response response = MessageFactory.create3489BindingResponse(
                mappedAddress, sourceAddress, changedAddress);

            try
            {
                stunStack.sendResponse(
                    evt.getTransactionID().getBytes(), response,
                    evt.getLocalAddress(), evt.getRemoteAddress());
                logger.finest("Binding Response Sent.");
            }
            catch (Exception e)
            {
                logger.log(
                    Level.INFO, "Failed to send " + response + " through "
                        + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
    }

    /**
     * Starts this <tt>BindingRequestListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            stunStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>ValidatedRequestListenerr</tt>. A stopped
     * <tt>ValidatedRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        stunStack.removeRequestListener(this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/ChannelBindRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
import org.jitsi.turnserver.stack.*;

/**
 * The class that would be handling and responding to incoming ChannelBind
 * requests that are validated and sends a success or error response
 * 
 * @author Aakash Garg
 */
public class ChannelBindRequestListener
    implements RequestListener
{

    /**
     * The <tt>Logger</tt> used by the <tt>ChannelBindRequestListener</tt> class
     * and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ChannelBindRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>ChannelBindrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new ChannelBindRequestListener
     * 
     * @param turnStack
     */
    public ChannelBindRequestListener(StunStack turnStack)
    {
        if (turnStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) turnStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
//            logger.finer("Received request " + evt);
        }
        
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CHANNELBIND_REQUEST)
        {
            logger.finest("Received Channel Bind request ");
            logger.finest("Event tran : "+evt.getTransactionID());
            
            Response response = null;
 
            TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = serverAddress.getTransport();
            FiveTuple fiveTuple =
                new FiveTuple(clientAddress, serverAddress, transport);
            
            Allocation allocation 
                = this.turnStack.getServerAllocation(fiveTuple);
            
            ChannelNumberAttribute channelNo =
                (ChannelNumberAttribute) message.getAttribute(
                    Attribute.CHANNEL_NUMBER);
            XorPeerAddressAttribute xorPeerAddress =
                (XorPeerAddressAttribute) message
                    .getAttribute(Attribute.XOR_PEER_ADDRESS);
            if(xorPeerAddress!=null)
            {
                xorPeerAddress.setAddress(xorPeerAddress.getAddress(),
                    evt.getTransactionID().getBytes());
            }
            
            logger.finest("Adding ChannelBind : "
                                    +(int)(channelNo.getChannelNumber())
                                    +", "+xorPeerAddress.getAddress());
            ChannelBind channelBind = new ChannelBind(
                                            xorPeerAddress.getAddress(),
                                            channelNo.getChannelNumber());

            Character errorCode = null;
            if(channelNo==null || xorPeerAddress==null)
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else if(!ChannelNumberAttribute.isValidRange(
                channelNo.getChannelNumber()))
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else if (allocation == null
                || allocation.isBadChannelRequest(channelBind))
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else if(!TurnStack.isIPAllowed(xorPeerAddress.getAddress()))
            {
                errorCode = ErrorCodeAttribute.FORBIDDEN;
            }
            else if(!allocation.canHaveMoreChannels())
            {
                errorCode = ErrorCodeAttribute.INSUFFICIENT_CAPACITY;
            }
            
            if(errorCode != null)
            {
                logger.finest("Creating ChannelBindError response : "
                                        +(int)errorCode);
                response  
                    = MessageFactory.createChannelBindErrorResponse(errorCode);
            }
            else
            {
                logger.finest("Creating ChannelBind sucess response");
                try
                {
                    logger.finer("Adding ChannelBind : "+channelBind);
                    allocation.addChannelBind(channelBind);
                }
                catch(IllegalArgumentException ex)
                {
                    logger.log(Level.FINEST,ex.getMessage());
                }
                response = MessageFactory.createChannelBindResponse();
            }
            
            try
            {
                turnStack.sendResponse(evt.getTransactionID().getBytes(),
                    response, evt.getLocalAddress(), evt.getRemoteAddress());
            }
            catch (Exception e)
            {
                logger.log(Level.INFO, "Failed to send " + response
                    + " through " + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
        else
        {
            return;
        }
    }

    /**
     * Starts this <tt>ChannelBindRequestListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>ChannelBindRequestListenerr</tt>. A stopped
     * <tt>ChannelBindRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.StunMessageEvent;
import org.ice4j.Transport;
import org.ice4j.TransportAddress;
import org.ice4j.attribute.Attribute;
import org.ice4j.attribute.AttributeFactory;
import org.ice4j.attribute.ConnectionIdAttribute;
import org.ice4j.attribute.ErrorCodeAttribute;
import org.ice4j.attribute.XorPeerAddressAttribute;
import org.ice4j.message.Message;
import org.ice4j.message.MessageFactory;
import org.ice4j.message.Response;
import org.ice4j.socket.IceTcpSocketWrapper;
import org.ice4j.stack.RequestListener;
import org.ice4j.stack.StunStack;
import org.jitsi.turnserver.stack.Allocation;
import org.jitsi.turnserver.stack.FiveTuple;
import org.jitsi.turnserver.stack.TurnStack;

/**
 * The class that would be handling and responding to incoming Connect requests
 * that are validated and sends a success or error response
 * 
 * @author Aakash Garg
 */
public class ConnectRequestListener
    implements RequestListener
{

    /**
     * The <tt>Logger</tt> used by the <tt>ConnectRequestListener</tt> class and
     * its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ConnectRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>ValidatedrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new ConnectRequestListener
     * 
     * @param turnStack
     */
    public ConnectRequestListener(StunStack stunStack)
    {
        this.turnStack = (TurnStack) stunStack;
    }

    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CONNECT_REQUEST)
        {
            logger.finer("Received Connect request " + evt);

            Character errorCode = null;
            XorPeerAddressAttribute peerAddress = null;
            FiveTuple fiveTuple = null;
            Response response = null;
            ConnectionIdAttribute connectionId = null;
            if (!message.containsAttribute(Attribute.XOR_PEER_ADDRESS))
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else
            {
                peerAddress =
                    (XorPeerAddressAttribute) message
                        .getAttribute(Attribute.XOR_PEER_ADDRESS);
                peerAddress.setAddress(
                    peerAddress.getAddress(), 
                    evt.getTransactionID().getBytes());
                logger.finest("Peer Address requested : "
                    + peerAddress.getAddress());
                TransportAddress clientAddress = evt.getRemoteAddress();
                TransportAddress serverAddress = evt.getLocalAddress();
                Transport transport = evt.getLocalAddress().getTransport();
                fiveTuple =
                    new FiveTuple(clientAddress, serverAddress, transport);
                Allocation allocation =
                    this.turnStack.getServerAllocation(fiveTuple);
                if (allocation == null)
                {
                    errorCode = ErrorCodeAttribute.ALLOCATION_MISMATCH;
                }
                else if(!allocation.isPermitted(peerAddress.getAddress())){
                    errorCode = ErrorCodeAttribute.FORBIDDEN;
                }
                else
                {
                    // code for processing the connect request.
                    connectionId = 
                        AttributeFactory.createConnectionIdAttribute();
                    logger.finest("Created ConnectionID : "
                        + connectionId.getConnectionIdValue());
                    try
                    {
                        Socket socket =
                            new Socket(peerAddress.getAddress().getAddress(),
                                peerAddress.getAddress().getPort());
                        socket.setSoTimeout(30*1000);
                        IceTcpSocketWrapper iceSocket =
                            new IceTcpSocketWrapper(socket);
                        this.turnStack.addSocket(iceSocket);
                    }
                    catch (IOException e)
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    /**
                     * TODO
                     * Create a new TCP connection to the peer from relay
                     * address. 
                     * wait for at-least 30 seconds. 
                     * If it fails then send 447 error code. 
                     **/
                    this.turnStack.addUnAcknowlededConnectionId(
                        connectionId.getConnectionIdValue(),
                        peerAddress.getAddress(), allocation);
                    logger.finest("Creating Connect Success Response.");
                    response =
                        MessageFactory.createConnectResponse(connectionId
                            .getConnectionIdValue());
                    
                }
            }
            if(errorCode != null){
                response = MessageFactory.createConnectErrorResponse(errorCode);
                logger.finest("error Code : "+(int)errorCode+ " on ConnectRequest");
            }
            try
            {
                logger.finest("Sending Connect Response");
                turnStack.sendResponse(
                    evt.getTransactionID().getBytes(), response,
                    evt.getLocalAddress(), evt.getRemoteAddress());
            }
            catch (Exception e)
            {
            System.err.println("Failed to send response");
                logger.log(
                    Level.INFO, "Failed to send " + response + " through "
                        + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
        else
        {
            return;
        }

    }

    /**
     * Starts this <tt>ConnectRequestListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>ConnectRequestListenerr</tt>. A stopped
     * <tt>ConnectRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectionAttemptIndicationListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.io.*;
import java.net.*;
import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.socket.*;
import org.ice4j.stack.*;
import org.ice4j.stunclient.*;

import org.jitsi.turnserver.*;
import org.jitsi.turnserver.stack.*;

/**
 * Class to handle events when a Connection Attempt Indication is received on
 * CLient Side.
 * 
 * @author Aakash Garg
 * 
 */
public class ConnectionAttemptIndicationListener
    extends IndicationListener
{
    /**
     * The <tt>Logger</tt> used by the <tt>DataIndicationListener</tt> class and
     * its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ConnectionAttemptIndicationListener.class.getName());

    /**
     * The request sender to use to send request to Turn server.
     */
    private BlockingRequestSender requestSender;

    /**
     * Constructor to create a ConnectionAttemptIndicationListener with
     * specified turnStack to use the requestSender will be null and a new
     * {@link BlockingRequestSender} will be created with new TCP socket to send
     * request to server.
     * 
     * @param turnStack the turnStack to use for processing.
     */
    public ConnectionAttemptIndicationListener(TurnStack turnStack)
    {
        super(turnStack);
    }

    /**
     * Constructor to create a ConnectionAttemptIndicationListener with
     * specified turnStack to use.
     * 
     * @param turnStack the turnStack to use for processing.
     * @param requestSender the requestSender to use to send request to server.
     */
    public ConnectionAttemptIndicationListener(TurnStack turnStack,
        BlockingRequestSender requestSender)
    {
        super(turnStack);
        this.requestSender = requestSender;
    }

    /**
     * The method to handle the incoming ConnectionAttempt Indications from Turn
     * Server.
     */
    @Override
    public void handleIndication(Indication ind, Allocation alloc)
    {
        if (ind.getMessageType() == Message.CONNECTION_ATTEMPT_INDICATION)
        {
            logger.finest("Received a connection attempt indication.");
            byte[] tranId = ind.getTransactionID();
            ConnectionIdAttribute connectionId =
                (ConnectionIdAttribute) ind
                    .getAttribute(Attribute.CONNECTION_ID);
            XorPeerAddressAttribute peerAddress =
                (XorPeerAddressAttribute) ind
                    .getAttribute(Attribute.XOR_PEER_ADDRESS);
            peerAddress.setAddress(
                peerAddress.getAddress(), tranId);
            logger
                .finest("Received a Connection Attempt Indication with connectionId-"
                    + connectionId.getConnectionIdValue()
                    + ", for peerAddress-" + peerAddress.getAddress());
            Socket socket;
            try
            {
                socket =
                    new Socket(InetAddress.getLocalHost().getHostAddress(),
                        3478);
                IceTcpSocketWrapper sockWrapper =
                    new IceTcpSocketWrapper(socket);
                this.getTurnStack().addSocket(
                    sockWrapper);
                TransportAddress localAddr =
                    new TransportAddress(sockWrapper.getLocalAddress(),
                        sockWrapper.getLocalPort(), Transport.TCP);
                logger.finest("New Local TCP socket chosen - " + localAddr);
                TransportAddress serverAddress =
                    new TransportAddress(InetAddress.getLocalHost(), 3478,
                        Transport.TCP);
                StunMessageEvent evt = null;
                try
                {
                    Request connectionBindRequest =
                        MessageFactory.createConnectionBindRequest(connectionId
                            .getConnectionIdValue());
                    TransactionID tranID =
                        TransactionID.createNewTransactionID();
                    connectionBindRequest.setTransactionID(tranID.getBytes());
                    if (this.requestSender == null)
                    {
                        logger.finest("Setting RequestSender");
                        this.requestSender =
                            new BlockingRequestSender(this.getTurnStack(),
                                localAddr);
                    }
                    logger.finest("Sending ConnectionBind Request to "
                        + serverAddress);
                    evt = requestSender.sendRequestAndWaitForResponse(
                        connectionBindRequest, serverAddress);
                    if (evt != null)
                    {
                        Message msg = evt.getMessage();
                        if (msg.getMessageType() == Message.CONNECTION_BIND_SUCCESS_RESPONSE)
                        {
                            logger
                                .finest("Received a ConnectionBind Sucess Response.");
                            String myMessage = "Aakash Garg";
                            RawMessage rawMessage =
                                RawMessage.build(myMessage.getBytes(),
                                    myMessage.length(), serverAddress,
                                    localAddr);
                            try
                            {
                                logger
                                    .finest("--------------- Thread will now sleep for 20 sec.");
                                Thread.sleep(20 * 1000);
                            }
                            catch (InterruptedException e)
                            {
                                System.err.println("Unable to stop thread");
                            }
                            logger
                                .finest(">>>>>>>>>>>> Sending a Test message : ");
                            byte[] data = myMessage.getBytes();
                            for (int i = 0; i < data.length; i++)
                            {
                                System.out.print(String.format(
                                    "%02X, ", data[i]));
                            }
                            this.getTurnStack().sendUdpMessage(
                                rawMessage, serverAddress,
                                requestSender.getLocalAddress());
                        }
                        else
                        {
                            logger
                                .finest("Received a ConnectionBind error Response - "
                                    + msg.getAttribute(Attribute.ERROR_CODE));
                        }
                    }
                    else
                    {
                        System.err
                            .println("No response received to ConnectionBind request");
                    }
                }
                catch (StunException e)
                {
                    logger.finest("Unable to send ConnectionBind request");
                }
            }
            catch (UnknownHostException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectionBindRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.io.*;
import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

import org.jitsi.turnserver.stack.*;

/**
 * The class that would be handling and responding to incoming ConnectionBind
 * requests that are validated and sends a success or error response
 * 
 * @author Aakash Garg
 */
public class ConnectionBindRequestListener
    implements RequestListener
{

    /**
     * The <tt>Logger</tt> used by the <tt>ConnectionBindRequestListener</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ConnectionBindRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>ConnectionBindrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new ConnectionBindRequestListener
     * 
     * @param turnStack
     */
    public ConnectionBindRequestListener(StunStack stunStack)
    {
        this.turnStack = (TurnStack)stunStack;
    }

    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CONNECTION_BIND_REQUEST)
        {
            Response response = null;
            Character errorCode = null;
            
            TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = evt.getLocalAddress().getTransport();
            logger.finer("Received ConnectBind request " + evt + ", from "
                + clientAddress + ", at " + serverAddress + " over "
                + transport);
            ConnectionIdAttribute connectionId = null;
            if (transport != Transport.TCP)
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
                logger.finest("Transport is not TCP.");
            }
            else if (!message.containsAttribute(Attribute.CONNECTION_ID))
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
                logger.finest("ConnectionID not found");
            }
            else
            {
                connectionId = (ConnectionIdAttribute) message
                    .getAttribute(Attribute.CONNECTION_ID);
                logger.finest("Requested ConnectionId - "
                    + connectionId.getConnectionIdValue());
                if (!this.turnStack.isUnacknowledged(connectionId
                    .getConnectionIdValue()))
                {
                    errorCode = ErrorCodeAttribute.BAD_REQUEST;
                    logger.finest("ConnectionId-"
                        + connectionId.getConnectionIdValue()
                        + " not present.");
                }
            }
            
            if (errorCode != null)
            {
                logger
                    .finest("Creating Connection Bind Error Response, errorCode:"
                        + (int) errorCode);
                response =
                    MessageFactory
                        .createConnectionBindErrorResponse(
                            ErrorCodeAttribute.BAD_REQUEST);
            }
            else
            {
                // processing logic.
                FiveTuple clientDataConnTuple =
                    new FiveTuple(clientAddress, serverAddress, transport);
                this.turnStack.acknowledgeConnectionId(
                    connectionId.getConnectionIdValue(), clientDataConnTuple);
                
                logger.finest("Creating ConnectionBind Success Response");
                response = MessageFactory.createConnectionBindResponse();
            }
            try
            {
                logger.finest("Sending ConnectionBind Response to "
                    + clientAddress + " through " + serverAddress);
                this.turnStack.sendResponse(
                    evt.getTransactionID().getBytes(), response, serverAddress,
                    clientAddress);
            }
            catch (StunException e)
            {
                logger.finest("Unable to send ConnectionBind Response to "
                    + clientAddress + " through " + serverAddress);
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        else
        {
            return;
        }
    }

    /**
     * Starts this <tt>ConnectionBindRequestListener</tt>. If it is not
     * currently running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>ConnectionBindRequestListenerr</tt>. A stopped
     * <tt>ConnectionBindRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/CreatePermissionRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
import org.jitsi.turnserver.stack.*;

/**
 * The class that would be handling and responding to incoming CreatePermission
 * requests that are CreatePermission and sends a success or error response
 * 
 * @author Aakash Garg
 */
public class CreatePermissionRequestListener
    implements RequestListener
{
    /**
     * The <tt>Logger</tt> used by the <tt>CreatePermissionRequestListener</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(CreatePermissionRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>CreatePermissionrequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new CreatePermissionRequestListener
     * 
     * @param turnStack
     */
    public CreatePermissionRequestListener(StunStack turnStack)
    {
        if (turnStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) turnStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.ice4j.stack.RequestListener#processRequest(org.ice4j.StunMessageEvent
     * )
     */
    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
//            logger.finer("Received request " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.CREATEPERMISSION_REQUEST)
        {
            logger.finest("Received create permission request ");
            logger.finest("Event tran : "+evt.getTransactionID());
            
            XorPeerAddressAttribute xorPeerAddressAttribute =
                (XorPeerAddressAttribute) message
                    .getAttribute(Attribute.XOR_PEER_ADDRESS);
            if(xorPeerAddressAttribute!=null)
            {
                xorPeerAddressAttribute.setAddress(
                    xorPeerAddressAttribute.getAddress(), 
                    evt.getTransactionID().getBytes());
            }
            // we should get multiple xor peer address attributes here.
            LifetimeAttribute lifetimeAttribute = 
                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);
            
            Response response = null;
            TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = serverAddress.getTransport();
            FiveTuple fiveTuple =
                new FiveTuple(clientAddress, serverAddress, transport);
            
            Allocation allocation 
                = this.turnStack.getServerAllocation(fiveTuple);
            
            Character errorCode = null;
            if (xorPeerAddressAttribute == null || allocation==null)
            {
                errorCode = ErrorCodeAttribute.BAD_REQUEST;
            }
            else if (!TurnStack.isIPAllowed(
                        xorPeerAddressAttribute.getAddress()))
            {
                logger.finest("Peer Address requested " 
                        + xorPeerAddressAttribute.getAddress()
                        +" "+TurnStack.isIPAllowed(
                            xorPeerAddressAttribute.getAddress()));
                errorCode = ErrorCodeAttribute.FORBIDDEN;
            }
            else if (!allocation.canHaveMorePermisions())
            {
                errorCode = ErrorCodeAttribute.INSUFFICIENT_CAPACITY;
            }
            if(errorCode!=null)
            {
                logger.finest("Creating error response : "+(int)errorCode);
                response = MessageFactory.createCreatePermissionErrorResponse(
                                errorCode);
            }
            else
            {   
                logger.finest("Creating success response.");
                TransportAddress peerAddress 
                    = xorPeerAddressAttribute.getAddress();
                Permission permission = null;
                if(lifetimeAttribute!=null)
                {
                     permission = new Permission(peerAddress,
                                         lifetimeAttribute.getLifetime());
                }
                else
                {
                    permission = new Permission(peerAddress);
                }
                
                logger.finest("Peer Address requested " 
                    + xorPeerAddressAttribute.getAddress()
                    +" "+TurnStack.isIPAllowed(
                        xorPeerAddressAttribute.getAddress()));
                allocation.addNewPermission(permission);
                logger.finest("Added permission to allocation.");
                response = MessageFactory.createCreatePermissionResponse();
            }
            try
            {
                turnStack.sendResponse(evt.getTransactionID().getBytes(),
                    response, evt.getLocalAddress(), evt.getRemoteAddress());
            }
            catch (Exception e)
            {
                logger.log(Level.INFO, "Failed to send " + response
                    + " through " + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
        else
        {
            return;
        }
    }

    /**
     * Starts this <tt>CreatePermissionRequestListener</tt>. If it is not
     * currently running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>CreatePermissionRequestListenerr</tt>. A stopped
     * <tt>CreatePermissionRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/DataIndicationListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.io.*;
import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;

import org.jitsi.turnserver.*;
import org.jitsi.turnserver.stack.*;

/**
 * Class to handle the incoming Data indications.
 * 
 * @author Aakash Garg
 * 
 */
public class DataIndicationListener extends IndicationListener 
{
    /**
     * The <tt>Logger</tt> used by the <tt>DataIndicationListener</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(DataIndicationListener.class.getName());

    /**
     * parametrised constructor.
     * 
     * @param turnStack
     *            the turnStack to set for this class.
     */
    public DataIndicationListener(TurnStack turnStack) 
    {
	super(turnStack);
    }

    /**
     * Handles the incoming data indication.
     * 
     * @param ind
     *            the indication to handle.
     * @param alloc
     *            the allocation associated with message.
     */
    @Override
    public void handleIndication(Indication ind, Allocation alloc) 
    {
	if (ind.getMessageType() == Message.DATA_INDICATION) 
	{
	    logger.finest("Received a Data Indication message.");
	    byte[] tran = ind.getTransactionID();

	    XorPeerAddressAttribute xorPeerAddress 
	    	= (XorPeerAddressAttribute) ind
		    .getAttribute(Attribute.XOR_PEER_ADDRESS);
	    xorPeerAddress.setAddress(xorPeerAddress.getAddress(), tran);
	    DataAttribute data = (DataAttribute) ind
		    .getAttribute(Attribute.DATA);

	    TransportAddress peerAddr = xorPeerAddress.getAddress();
	    try 
	    {
		String line = new String(data.getData(), "UTF-8");
//		System.out.println(line);
		logger.finest("Data Indiaction message from  " + peerAddr
			+ " is " + line);
/*		System.out.println("Received a Data indiction from " + peerAddr
			+ ", message : " + line);
*/	    } catch (UnsupportedEncodingException e) 
{
		System.err.println("Unable to convert to String!");
	    }
	}
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/PeerTcpConnectEventListner.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.ice4j.StunException;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

import org.jitsi.turnserver.socket.*;
import org.jitsi.turnserver.stack.*;

/**
 * Class to handle events when Peer tries to establish a TCP connection to a
 * Server Socket (generally Relay Address).
 * 
 * @author Aakash Garg
 * 
 */
public class PeerTcpConnectEventListner
    implements TcpConnectEventListener
{

    /**
     * The <tt>Logger</tt> used by the <tt>FiveTuple</tt> class and its
     * instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(PeerTcpConnectEventListner.class.getName());

    private final TurnStack turnStack;

    public PeerTcpConnectEventListner(TurnStack turnStack)
    {
        this.turnStack = turnStack;
    }

    @Override
    public void onConnect(TcpConnectEvent event)
    {
        logger.setLevel(Level.FINEST);
        logger.finest("Received a connect event src:" + event.getLocalAdress()
            + ", dest:" + event.getRemoteAdress());
        Allocation allocation =
            this.turnStack.getServerAllocation(event.getLocalAdress());
        if (allocation == null)
        {
            logger.finest("Allocation not found for relay : "
                + event.getLocalAdress());
        }
        else if (allocation.isPermitted(event.getRemoteAdress()))
        {
            try
            {
                ConnectionIdAttribute connectionId =
                    AttributeFactory.createConnectionIdAttribute();
                logger.finest("Created ConnectionId - "
                    + connectionId.getConnectionIdValue() + " for client "
                    + allocation.getClientAddress());
                TransactionID tranID = TransactionID.createNewTransactionID();
                Indication connectionAttemptIndication =
                    MessageFactory.createConnectionAttemptIndication(
                        connectionId.getConnectionIdValue(),
                        event.getRemoteAdress(), tranID.getBytes());
                this.turnStack.addUnAcknowlededConnectionId(
                    connectionId.getConnectionIdValue(),
                    event.getRemoteAdress(), allocation);
                logger.finest("Sending Connection Attempt Indication.");
                this.turnStack.sendIndication(
                    connectionAttemptIndication, allocation.getClientAddress(),
                    allocation.getServerAddress());
            }
            catch (StunException e)
            {
                logger
                    .finest("Unable to send Connection Attempt Indiacation to "
                        + allocation.getClientAddress());
            }
        }
        else
        {
            logger.finest("permission not installed for - "
                + event.getRemoteAdress());
        }
        // this.turnStack.add
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/RefreshRequestListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;
import org.jitsi.turnserver.stack.*;

/**
 * The class that would be handling and responding to incoming Refresh requests
 * that are validated and sends a success or error response
 * 
 * @author Aakash Garg
 */
public class RefreshRequestListener
    implements RequestListener
{
    /**
     * The <tt>Logger</tt> used by the <tt>RefreshRequestListener</tt> class and
     * its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(RefreshRequestListener.class.getName());

    private final TurnStack turnStack;

    /**
     * The indicator which determines whether this
     * <tt>RefreshRequestListener</tt> is currently started.
     */
    private boolean started = false;

    /**
     * Creates a new RefreshRequestListener
     * 
     * @param turnStack
     */
    public RefreshRequestListener(StunStack turnStack)
    {
        if (turnStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) turnStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    /**
     * (non-Javadoc)
     * 
     * @see org.ice4j.stack.RequestListener#processRequest(org.ice4j.StunMessageEvent)
     */
    @Override
    public void processRequest(StunMessageEvent evt)
        throws IllegalArgumentException
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);            
//            logger.finer("Received request " + evt);
        }
        Message message = evt.getMessage();
        if (message.getMessageType() == Message.REFRESH_REQUEST)
        {
            logger.finer("Received refresh request " + evt);

            LifetimeAttribute lifetimeAttribute =
                (LifetimeAttribute) message.getAttribute(Attribute.LIFETIME);
            
            Response response = null;
            TransportAddress clientAddress = evt.getRemoteAddress();
            TransportAddress serverAddress = evt.getLocalAddress();
            Transport transport = serverAddress.getTransport();
            FiveTuple fiveTuple =
                new FiveTuple(clientAddress, serverAddress, transport);
            
            Allocation allocation =
                this.turnStack.getServerAllocation(fiveTuple);
            if (allocation != null)
            {
                if (lifetimeAttribute != null)
                {
		    logger.finest("Refreshing allocation with relay addr "
			    + allocation.getRelayAddress() + " with lifetime "
			    + lifetimeAttribute.getLifetime());
                    allocation.refresh(lifetimeAttribute.getLifetime());
                    response = MessageFactory.createRefreshResponse(
                            (int) allocation.getLifetime());
                }
                else
                {
		    logger.finest("Refreshing allocation with relay addr "
			    + allocation.getRelayAddress()
			    + " with default lifetime");
                    allocation.refresh();
                    response = MessageFactory.createRefreshResponse(
                            (int) allocation.getLifetime());
                }
            }
            else
            {
        	logger.finest("Allocation mismatch error");
                response = MessageFactory.createRefreshErrorResponse(
                            ErrorCodeAttribute.ALLOCATION_MISMATCH);
            }
            try
            {
                turnStack.sendResponse(evt.getTransactionID().getBytes(),
                    response, evt.getLocalAddress(), evt.getRemoteAddress());
            }
            catch (Exception e)
            {
                logger.log(Level.INFO, "Failed to send " + response
                    + " through " + evt.getLocalAddress(), e);
                // try to trigger a 500 response although if this one failed,
                throw new RuntimeException("Failed to send a response", e);
            }
        }
        else
        {
            return;
        }

    }

    /**
     * Starts this <tt>RefreshRequestListener</tt>. If it is not currently
     * running, does nothing.
     */
    public void start()
    {
        if (!started)
        {
            turnStack.addRequestListener(this);
            started = true;
        }
    }

    /**
     * Stops this <tt>RefreshRequestListenerr</tt>. A stopped
     * <tt>ValidatedRequestListenerr</tt> can be restarted by calling
     * {@link #start()} on it.
     */
    public void stop()
    {
        turnStack.removeRequestListener(this);
        started = false;
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/listeners/SendIndicationListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.listeners;

import java.util.logging.Logger;

import org.ice4j.*;
import org.ice4j.attribute.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

import org.jitsi.turnserver.*;
import org.jitsi.turnserver.stack.*;

/**
 * Class to handle the incoming Send indications.
 * 
 * @author Aakash Garg
 * 
 */
public class SendIndicationListener extends IndicationListener 
{
    /**
     * The <tt>Logger</tt> used by the <tt>SendIndicationListener</tt>
     * class and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(SendIndicationListener.class.getName());

    /**
     * parametrised constructor.
     * 
     * @param turnStack
     *            the turnStack to set for this class.
     */
    public SendIndicationListener(TurnStack turnStack) 
    {
	super(turnStack);
    }

    /**
     * Handles the incoming send indication.
     * 
     * @param ind
     *            the indication to handle.
     * @param alloc
     *            the allocation associated with message.
     */
    @Override
    public void handleIndication(Indication ind, Allocation alloc) 
    {
	if(ind.getMessageType()==Message.SEND_INDICATION)
	{
	    logger.finest("Received a Send Indication message.");
	    byte[] tran = ind.getTransactionID();
	    XorPeerAddressAttribute xorPeerAddress
	    	= (XorPeerAddressAttribute) ind
	    		.getAttribute(Attribute.XOR_PEER_ADDRESS);
	    xorPeerAddress.setAddress(xorPeerAddress.getAddress(), tran);
	    DataAttribute data 
	    	= (DataAttribute) ind.getAttribute(Attribute.DATA);
	    TransportAddress peerAddr = xorPeerAddress.getAddress();
	    if(alloc!=null && alloc.isPermitted(peerAddr))
	    {
		RawMessage udpMessage = RawMessage.build(data.getData(),
			data.getDataLength(), peerAddr, alloc.getRelayAddress());
		try 
		{
		    this.getTurnStack().sendUdpMessage(udpMessage, peerAddr,
			    alloc.getRelayAddress());
		    logger.finest("Sent SendIndiaction to " + peerAddr
			    + " from " + alloc.getRelayAddress());
		} catch (StunException e) {
		    System.err.println("Unable to send message.");
		}
	    }
	    // else silently ignore the indication.
	}
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/socket/IceTcpEventizedServerSockerWrapper.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.socket;

import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.ice.*;
import org.ice4j.socket.*;

/**
 * Class for eventized TCP server Socket where event is when someone tries to
 * connect to the given server Socket of the class.
 * 
 * @author Aakash Garg
 * 
 */
public class IceTcpEventizedServerSockerWrapper
    extends IceSocketWrapper
    implements TcpConnectEventGenerator
{

    /**
     * The <tt>Logger</tt> used by the <tt>LocalCandidate</tt> class and its
     * instances for logging output.
     */
    private static Logger logger = Logger
        .getLogger(IceTcpEventizedServerSockerWrapper.class.getName());

    /**
     * Thread that will wait new connections.
     */
    private Thread acceptThread = null;

    /**
     * The wrapped TCP ServerSocket.
     */
    private final ServerSocket serverSocket;

    /**
     * If the socket is still listening.
     */
    private boolean isRun = false;

    private TcpConnectEventListener listener;

    /**
     * STUN stack.
     */
    private final Component component;

    /**
     * List of TCP client sockets.
     */
    private final List<Socket> sockets = new ArrayList<Socket>();

    public IceTcpEventizedServerSockerWrapper(ServerSocket serverSocket,
        Component component)
    {
        this.serverSocket = serverSocket;
        this.component = component;
        acceptThread = new ThreadAccept();
        acceptThread.start();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void send(DatagramPacket p) throws IOException
    {
        System.err.println("Send called in IceTcpServerSocketWrapper.");
        /* Do nothing for the moment */
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void receive(DatagramPacket p) throws IOException
    {
        System.err.println("Receive called in IceTcpServerSocketWrapper.");
        /* Do nothing for the moment */
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void close()
    {
        try
        {
            isRun = false;
            serverSocket.close();
            for (Socket s : sockets)
            {
                s.close();
            }
        }
        catch (IOException e)
        {
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public InetAddress getLocalAddress()
    {
        return serverSocket.getInetAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getLocalPort()
    {
        return serverSocket.getLocalPort();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SocketAddress getLocalSocketAddress()
    {
        return serverSocket.getLocalSocketAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Socket getTCPSocket()
    {
        if (sockets.size() > 0)
        {
            return sockets.get(0);
        }

        return null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public DatagramSocket getUDPSocket()
    {
        return null;
    }

    @Override
    public void setEventListener(TcpConnectEventListener listener)
    {
        this.listener = listener;
    }

    @Override
    public void removeEventListener()
    {
        this.listener = null;
    }

    @Override
    public void fireConnectEvent(TcpConnectEvent event)
    {
        if (this.listener != null)
            this.listener.onConnect(event);
        else
            logger.finest("Listener not registered");
    }

    /**
     * Thread that will wait for new TCP connections.
     * 
     */
    private class ThreadAccept
        extends Thread
    {
        /**
         * Thread entry point.
         */
        @Override
        public void run()
        {
            isRun = true;

            while (isRun)
            {
                try
                {
                    Socket tcpSocket = serverSocket.accept();

                    if (tcpSocket != null)
                    {
                        MultiplexingSocket multiplexingSocket =
                            new MultiplexingSocket(tcpSocket);
                        component.getParentStream().getParentAgent()
                            .getStunStack().addSocket(
                                new IceTcpSocketWrapper(multiplexingSocket));

                        sockets.add(multiplexingSocket);
                        String[] serverIpPort =
                            serverSocket.getLocalSocketAddress().toString()
                                .replaceAll(
                                    "/", "").split(
                                    ":");
                        TransportAddress localAddr =
                            new TransportAddress(InetAddress.getLocalHost(),
                                Integer.parseInt(serverIpPort[1]),
                                Transport.TCP);
                        
                        String[] remoteIpPort =
                            tcpSocket.getRemoteSocketAddress().toString()
                                .replaceAll(
                                    "/", "").split(
                                    ":");
                        TransportAddress remoteAddr =
                            new TransportAddress(remoteIpPort[0],
                                Integer.parseInt(remoteIpPort[1]),
                                Transport.TCP);
                        logger.finest("Connection Request from "+remoteAddr+" to "+localAddr);
                        TcpConnectEvent event =
                            new TcpConnectEvent(localAddr, remoteAddr);
                        IceTcpEventizedServerSockerWrapper.this
                            .fireConnectEvent(event);
                    }
                }
                catch (IOException e)
                {
                    logger.info("Failed to accept TCP socket " + e);
                }
            }
        }
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEvent.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.socket;

import org.ice4j.TransportAddress;

/**
 * Represents the TCP connect event on the Server Socket.
 * 
 * @author Aakash Garg
 * 
 */
public class TcpConnectEvent
{
    private final TransportAddress localAdress;
    
    private final TransportAddress remoteAdress;

    /**
     * @param localAdress
     * @param remoteAdress
     */
    public TcpConnectEvent(TransportAddress localAdress,
        TransportAddress remoteAdress)
    {
        this.localAdress = localAdress;
        this.remoteAdress = remoteAdress;
    }

    public TransportAddress getLocalAdress()
    {
        return localAdress;
    }

    public TransportAddress getRemoteAdress()
    {
        return remoteAdress;
    }   

    
    
}


================================================
FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEventGenerator.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.socket;

/**
 * Represents the source of generating the TCP connect events.
 * 
 * @author Aakash Garg
 * 
 */
public interface TcpConnectEventGenerator
{
    public void setEventListener(TcpConnectEventListener listener);
    
    public void removeEventListener();
    
    public void fireConnectEvent(TcpConnectEvent event);
}


================================================
FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEventListener.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.socket;

/**
 * Represents the TCP Connect Event Listener.
 * 
 * @author Aakash Garg.
 * 
 */
public interface TcpConnectEventListener
{
    public void onConnect(TcpConnectEvent event);
    
}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/Allocation.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Logger;

import org.ice4j.Transport;
import org.ice4j.TransportAddress;

/**
 * This class is an implementation of Allocations in TURN server.
 * 
 * @author Aakash Garg
 * 
 */
public class Allocation
{
    /**
     * Our class logger.
     */
    private static final Logger logger = Logger.getLogger(Allocation.class
        .getName());

    /**
     * represents the relay address associated with this Allocation.
     */
    private final TransportAddress relayAddress;

    /**
     * Represents the FiveTuple associated with this Allocation.
     */
    private final FiveTuple fiveTuple;

    /**
     * Represents the username associated with this Allocation.
     */
    private final String username;

    /**
     * represents the password associated with this Allocation.
     */
    private final String password;

    /**
     * The time in milliseconds when the Allocation will expire.
     */
    private long expirationTime = -1;

    /**
     * Determines whether or not the Allocation has expired.
     */
    private boolean expired = false;

    /**
     * The default lifetime allowed for a Allocation.
     */
    public static final long DEFAULT_LIFETIME = 10 * 60 * 1000;

    /**
     * The max lifetime allowed for a Allocation.
     */
    public static final long MAX_LIFETIME = 60 * 60 * 1000;

    /**
     * The maximum no of Permissions per Allocation.
     */
    public static final int MAX_PERMISSIONS = 10;

    /**
     * The Maximum no of ChannelBinds per Allocation.
     */
    public static final int MAX_CHANNELBIND = 10;

    /**
     * The <tt>Thread</tt> which expires the <tt>Permission</tt>s of this
     * <tt>Allocation</tt> and removes them from {@link #permissions}.
     */
    private Thread permissionExpireThread;

    /**
     * Represents the permissions associated with peerAddress IP installed for
     * this Allocation.
     */
    private final HashMap<TransportAddress, Permission> permissions =
        new HashMap<TransportAddress, Permission>();

    /**
     * The <tt>Thread</tt> which expires the <tt>ChannelBind</tt>s of this
     * <tt>Allocation</tt> and removes them from {@link #channelBindings}.
     */
    private Thread channelBindExpireThread;

    /**
     * Represents the Channel Bindings associated with this Allocation.
     */
    private final HashMap<Character, ChannelBind> channelBindings =
        new HashMap<Character, ChannelBind>();

    /**
     * Contains the mapping of peerAdress of ChannelBinds to Channelno. This is
     * used to check the peerAddress while creating new Permissions and
     * ChannelBinds.
     */
    private final HashMap<TransportAddress, Character> peerToChannelMap =
        new HashMap<TransportAddress, Character>();

    /**
     * Maps one-to-one from ConnecionID to Data Connection.
     */
    private final HashMap<Integer,FiveTuple> connIdToDataConnMap
         = new HashMap<Integer,FiveTuple>();
    
    /**
     * Maps one-to-one from ConnecionID to Peer TCP Connection.
     */
    private final HashMap<Integer,FiveTuple> connIdToPeerConnMap
        = new HashMap<Integer,FiveTuple>();
    
    /**
     * Constructor to instantiate an Allocation without a username and password.
     * 
     * @param relayAddress the realyAddress associated with this Allocation.
     * @param fiveTuple the fiveTuple associated with this Allocation.
     */
    public Allocation(  TransportAddress relayAddress, 
                        FiveTuple fiveTuple)
    {
        this(relayAddress, fiveTuple, null, null);
    }

    /**
     * Constructor to instantiate an Allocation without a username and password
     * with the lifetime value.
     * 
     * @param relayAddress the realyAddress associated with this Allocation.
     * @param fiveTuple the fiveTuple associated with this Allocation.
     * @param lifetime the lifetime for this Allocation.
     */
    public Allocation(  TransportAddress relayAddress, 
                        FiveTuple fiveTuple,
                        long lifetime)
    {
        this(relayAddress, fiveTuple, null, null, lifetime);
    }

    /**
     * Constructor to instantiate an Allocation with given relayAddress,
     * fiveTuple, username, passowrd and with default lifetime value.
     * 
     * @param relayAddress the realyAddress associated with this Allocation.
     * @param fiveTuple the fiveTuple associated with this Allocation.
     * @param username the username associated with this Allocation.
     * @param password the password associated with this Allocation.
     */
    public Allocation(  TransportAddress relayAddress, 
                        FiveTuple fiveTuple,
                        String username, 
                        String password)
    {
        this(relayAddress, fiveTuple, username, password,
            Allocation.DEFAULT_LIFETIME);
    }

    /**
     * Constructor to instantiate an Allocation with given relayAddress,
     * fiveTuple, username, passowrd and with default lifetime value.
     * 
     * @param relayAddress the realyAddress associated with this Allocation.
     * @param fiveTuple the fiveTuple associated with this Allocation.
     * @param username the username associated with this Allocation.
     * @param password the password associated with this Allocation.
     * @param lifetime the lifetime for this allocation.
     */
    public Allocation(  TransportAddress relayAddress, 
                        FiveTuple fiveTuple,
                        String username, 
                        String password, 
                        long lifetime)
    {
        this.relayAddress = relayAddress;
        this.fiveTuple = fiveTuple;
        this.username = username;
        this.password = password;
        this.setLifetime(lifetime);
    }

    /**
     * returns the fiveTuple associated with this Allocation.
     */
    public FiveTuple getFiveTuple()
    {
        return this.fiveTuple;
    }

    /**
     * Returns the relayAddress associated with this Allocation.
     */
    public TransportAddress getRelayAddress()
    {
        return this.relayAddress;
    }

    /**
     * Returns the clientAddress associated with this Allocation.
     * The client address who instianted this allocation.
     */
    public TransportAddress getClientAddress()
    {
        return this.getFiveTuple().getClientTransportAddress();
    }    
    
    /**
     * Returns the serverAddress associated with this Allocation.
     * The serverAddress on which this allocation request is received.
     */
    public TransportAddress getServerAddress()
    {
        return this.getFiveTuple().getServerTransportAddress();
    }
    
    /**
     * Returns the Client Data Connection corresponding to Connection Id for
     * which ConnectionBind Request has been received.
     * 
     * @param connectionId the ConnectionId for which Client Data Connection is
     *            to be returned.
     * @return Client Data Connection if exists else null.
     */
    public FiveTuple getDataConnection(int connectionId){
        return this.connIdToDataConnMap.get(connectionId);
    }
    
    /**
     * Returns the Peer TCP Data Connection corresponding to Connection Id for
     * which ConnectionBind Request has been received.
     * 
     * @param connectionId the ConnectionId for which Peer TCP Data Connection is
     *            to be returned.
     * @return Peer TCP Data Connection if exists else null.
     */
    public FiveTuple getPeerTCPConnection(int connectionId){
        return this.connIdToPeerConnMap.get(connectionId);
    }

    /**
     * Adds the Connection Id with corresponding Client Data Connection to for
     * which ConnectionBind Request has been received.
     * 
     * @param connectionId the ConnectionId.
     * @param clientDataConn Client Data Connection to corresponding
     *            ConnectionId.
     */
    public void addDataConnection(int connectionId, FiveTuple clientDataConn)
    {
        this.connIdToDataConnMap.put(
            connectionId, clientDataConn);
    }

    /**
     * Adds the Connection Id corresponding to Peer TCP Data Connection for
     * which ConnectionBind Request has been received.
     * 
     * @param connectionId the ConnectionId.
     * @param peerDataConn Peer TCP Data Connection to corresponding
     *            ConnectionId.
     */
    public void addPeerTCPConnection(int connectionId, FiveTuple peerDataConn)
    {
        this.connIdToPeerConnMap.put(connectionId,peerDataConn);
    }
    
    /**
     * Removes the Client Data Connection with corresponding to Connection Id.
     * 
     * @param connectionId the ConnectionId corresponding to Client Data
     *            Connection.
     */
    public void removeDataConnection(int connectionId)
    {
        this.connIdToDataConnMap.remove(connectionId);
    }

    /**
     * Removes the Peer TCP Data Connection corresponding to Connection Id.
     * 
     * @param connectionId the ConnectionId corresponding to Client Data
     *            Connection.
     */
    public void removePeerTCPConnection(int connectionId)
    {
        this.connIdToPeerConnMap.remove(connectionId);
    }    
    
    /**
     * Returns the lifetime associated with this Allocation. If the allocation
     * is expired it returns 0.
     */
    public long getLifetime()
    {
        if (!isExpired())
        {
            return (this.expirationTime - System.currentTimeMillis());
        }
        else
        {
            return 0;
        }
    }

    /**
     * Sets the time to expire in milli-seconds for this allocation. Max
     * lifetime can be Allocation.MAX_LIFEIME.
     * 
     * @param lifetime the lifetime for this Allocation.
     */
    public void setLifetime(long lifetime)
    {
        synchronized (this)
        {
            this.expirationTime = System.currentTimeMillis() 
                + Math.min(lifetime * 1000, Allocation.MAX_LIFETIME);
        }
    }

    /**
     * Refreshes the allocation with the DEFAULT_LIFETIME value.
     */
    public void refresh()
    {
        this.setLifetime(Allocation.DEFAULT_LIFETIME);
    }

    /**
     * refreshes the allocation with given lifetime value.
     * 
     * @param lifetime the required lifetime of allocation.
     */
    public void refresh(int lifetime)
    {
        this.setLifetime(lifetime);
    }

    /**
     * Start the Allocation. This launches the countdown to the moment the
     * Allocation would expire.
     */
    public synchronized void start()
    {
        synchronized (this)
        {
            if (expirationTime == -1)
            {
                expired = false;
                expirationTime = DEFAULT_LIFETIME + System.currentTimeMillis();
            }
            else
            {
                throw new IllegalStateException(
                    "Allocation has already been started!");
            }
        }
    }
    
    /**
     * Determines whether this <tt>Allocation</tt> is expired now.
     * 
     * @return <tt>true</tt> if this <tt>Allocation</tT> is expired now;
     *         otherwise, <tt>false</tt>
     */
    public boolean isExpired()
    {
        return isExpired(System.currentTimeMillis());
    }

    /**
     * Expires the Allocation. Once this method is called the Allocation is
     * considered terminated.
     */
    public synchronized void expire()
    {
        expired = true;
        /*
         * TurnStack has a background Thread running with the purpose of
         * removing expired Allocations.
         */
    }

    /**
     * Determines whether this <tt>Allocation</tt> will be expired at a specific
     * point in time.
     * 
     * @param now the time in milliseconds at which the <tt>expired</tt> state
     *            of this <tt>Allocation</tt> is to be returned
     * @return <tt>true</tt> if this <tt>Allocation</tt> will be expired at the
     *         specified point in time; otherwise, <tt>false</tt>
     */
    public synchronized boolean isExpired(long now)
    {
        if (expirationTime == -1)
            return false;
        else if (expirationTime < now)
            return true;
        else
            return expired;
    }

    /**
     * Adds a new Permission for this Allocation.
     * 
     * @param peerIP the peer IP address foe which to create this permission to
     *            be added to this allocation.
     */
    public void addNewPermission(TransportAddress peerIP)
    {
        TransportAddress peerIp =
            new TransportAddress(peerIP.getAddress(), 0, Transport.UDP);
        Permission permission = new Permission(peerIP);
        this.addNewPermission(permission);
    }

    /**
     * Adds a new Permission for this Allocation.
     * 
     * @param permission the permission to be added to this allocation.
     */
    public void addNewPermission(Permission permission)
    {
        TransportAddress peerAddr =
            new TransportAddress(permission.getIpAddress().getAddress(), 0,
                Transport.UDP);
        if (this.permissions.containsKey(peerAddr))
        {
            this.permissions.get(permission.getIpAddress()).refresh();
        }
        else if (!this.canHaveMorePermisions())
        {
            return;
        }
        else
        {
            this.permissions.put(
                permission.getIpAddress(), permission);
            maybeStartPermissionExpireThread();
        }
    }

    /**
     * Binds a new Channel to this Allocation.
     * If an existing ChannelBind is found it is refreshed
     * else a new ChannelBind and permission is added.
     * 
     * @param channelBind the channelBind to be added to this allocation.
     * @throws IllegalArgumentException if the channelNo of the channelBind to
     *             be added is already occupied.
     */
    public void addChannelBind(ChannelBind channelBind)
    {
        TransportAddress peerAddr =
            new TransportAddress(
                    channelBind.getPeerAddress().getAddress(),
                    0, 
                    Transport.UDP);
        if (isBadChannelRequest(channelBind))
        {
            throw new IllegalArgumentException("400: BAD REQUEST");
        }
        else if(!channelBindings.containsKey(channelBind.getChannelNo()) 
               && !peerToChannelMap.containsKey(channelBind.getPeerAddress()))
        {
            synchronized(this.channelBindings)
            {
                this.channelBindings.put(   channelBind.getChannelNo(),
                                            channelBind);
            }
            synchronized(this.peerToChannelMap)
            {
                this.peerToChannelMap.put(
                    channelBind.getPeerAddress(), channelBind.getChannelNo());
            }
        }
        else
        {
            synchronized(this.channelBindings)
            {
                this.channelBindings.get(channelBind.getChannelNo()).refresh();
            }
        }
        this.addNewPermission(peerAddr);
        maybeStartChannelBindExpireThread();
    }

    /**
     * Determines whether the ChannelBind request is a BAD request or not.
     * A request is BAD when the same client sends a ChannelBind Request and
     * channel no or peerAddress coincides with existing channel bindings.
     * A request is not bad if the channel no and peerAddress in the ChannelBind
     * request are same as that in current mapping.
     * 
     * @param channelBind the channelBind request to validate.
     * @return true if request is a BAD request.
     */
    public boolean isBadChannelRequest(ChannelBind channelBind)
    {
        boolean hasChannelNo =
            this.channelBindings.containsKey(channelBind.getChannelNo());
        boolean hasPeerAddr =
            this.peerToChannelMap.containsKey(channelBind.getPeerAddress());
        if(hasChannelNo && hasPeerAddr)
        {
            if (this.channelBindings.get(
                channelBind.getChannelNo()).equals(
                    channelBind.getPeerAddress()))
            {
                return false;
            }
      }
      else if(!hasChannelNo && !hasPeerAddr)
      {
          return false;
      }
        return true;
    }
    
    /**
     * Removes the channelBind associated with this channlNo from this
     * allocation.
     * 
     * @param channelNo the channelNo for which the ChannelBind to delete.
     * @return the ChannnelBindingf associated with this channelNo.
     */
    public ChannelBind removeChannelBind(char channelNo)
    {
        ChannelBind channelBind = null;
        synchronized (this.channelBindings)
        {
            channelBind = this.channelBindings.remove(channelNo);
        }
        return channelBind;
    }

    /**
     * Checks if the Permission is installed for the peerAddress. The port value
     * is ignored.
     * 
     * @param peerAddress
     *            the peerAddress for which to check permission.
     * @return true if permission is installed for peerAddress else false.
     */
    public boolean isPermitted(TransportAddress peerAddress)
    {
        peerAddress =
            new TransportAddress(peerAddress.getAddress(), 0,
                peerAddress.getTransport());
        if (this.permissions.containsKey(peerAddress))
        {
            return true;
        }
        return false;
    }
    
    /**
     * Checks if the specified channel no is binded to this allocation.
     * 
     * @param channelNo
     *            the channel number to check.
     * @return true if the specified channel no. is installed for this
     *         allocation.
     */
    public boolean containsChannel(char channelNo)
    {
	return this.channelBindings.containsKey(channelNo);
    }

    /**
     * Gets the channelNO for the specified peerAddress.
     * @param peerAddress the peerAddress for which to get the channel.
     * @return channelNo is channelNo is found, else 0x1000.
     */
    public char getChannel(TransportAddress peerAddress)
    {
	char val = 0x1000;
	if(this.peerToChannelMap.containsKey(peerAddress))
	{
	    return this.peerToChannelMap.get(peerAddress);
	}
	return val;
    }
    
    /**
     * Gets the peerAddress associated with specified channelNo.
     * 
     * @param channelNo
     *            the channel no for which to get the peerAddress.
     * @return peerAddress the peerAddress associated with the channelNo in this
     *         allocation.
     */
    public TransportAddress getPeerAddr(char channelNo)
    {
	ChannelBind cb = this.channelBindings.get(channelNo);
	if(cb!=null)
	{
	    return cb.getPeerAddress();
	}
	return null;
    }
    
    /**
     * Determines if more permissions can be added to this allocation.
     * 
     * @return true if no of permissions are less than maximum allowed
     *         permissions per Allocation.
     */
    public boolean canHaveMorePermisions()
    {
        return (this.permissions.size() < MAX_PERMISSIONS);
    }

    /**
     * Determines if more channels can be added to this allocation.
     * 
     * @return true if no of channels are less than maximum allowed channels per
     *         Allocation.
     */
    public boolean canHaveMoreChannels()
    {
        return (this.channelBindings.size() < MAX_CHANNELBIND);
    }

    /**
     * Initialises and starts {@link #channelBindExpireThread} if necessary.
     */
    public void maybeStartChannelBindExpireThread()
    {
        synchronized (channelBindings)
        {
            if (!channelBindings.isEmpty() && (channelBindExpireThread == null))
            {
                Thread t = new Thread()
                {
                    @Override
                    public void run()
                    {
                        runInAllocationChannelBindExpireThread();
                    }
                };

                t.setDaemon(true);
                t.setName(getClass().getName() + ".channelBindExpireThread");

                boolean started = false;

                channelBindExpireThread = t;
                try
                {
                    t.start();
                    started = true;
                }
                finally
                {
                    if (!started && (channelBindExpireThread == t))
                        channelBindExpireThread = null;
                }
            }
        }
    }

    /**
     * Runs in {@link #channelBindExpireThread} and expires the
     * <tt>ChannelBind</tt>s of this <tt>Allocation</tt> and removes them from
     * {@link #channelBindingings}.
     */
    private void runInAllocationChannelBindExpireThread()
    {
        try
        {
            long idleStartTime = -1;

            do
            {
                synchronized (channelBindings)
                {
                    try
                    {
                        channelBindings.wait(ChannelBind.MAX_LIFETIME);
                    }
                    catch (InterruptedException ie)
                    {
                    }

                    /*
                     * Is the current Thread still designated to expire the
                     * ChannelBinds of this Allocation?
                     */
                    if (Thread.currentThread() != channelBindExpireThread)
                        break;

                    long now = System.currentTimeMillis();

                    /*
                     * Has the current Thread been idle long enough to merit
                     * disposing of it?
                     */
                    if (channelBindings.isEmpty())
                    {
                        if (idleStartTime == -1)
                            idleStartTime = now;
                        else if (now - idleStartTime > 60 * 1000)
                            break;
                    }
                    else
                    {
                        // Expire the ChannelBinds of this Allocation.

                        idleStartTime = -1;

                        for (Iterator<ChannelBind> i =
                            channelBindings.values().iterator(); i.hasNext();)
                        {
                            ChannelBind channelBind = i.next();

                            if (channelBind == null)
                            {
                                i.remove();
                            }
                            else if (channelBind.isExpired(now))
                            {
                                logger.finer("ChannelBind " + channelBind
                                    + " expired");
                                i.remove();
                                this.peerToChannelMap.remove(
                                    channelBind.getPeerAddress());
                                channelBind.expire();
                            }
                        }
                    }
                }
            }
            while (true);
        }
        finally
        {
            synchronized (channelBindings)
            {
                if (channelBindExpireThread == Thread.currentThread())
                    channelBindExpireThread = null;
                /*
                 * If channelBindExpireThread dies unexpectedly and yet it is
                 * still necessary, resurrect it.
                 */
                if (channelBindExpireThread == null)
                    maybeStartChannelBindExpireThread();
            }
        }
    }

    /**
     * Initialises and starts {@link #permissionExpireThread} if necessary.
     */
    public void maybeStartPermissionExpireThread()
    {
        synchronized (permissions)
        {
            if (!permissions.isEmpty() && (permissionExpireThread == null))
            {
                Thread t = new Thread()
                {
                    @Override
                    public void run()
                    {
                        runInAllocationPermissionExpireThread();
                    }
                };

                t.setDaemon(true);
                t.setName(getClass().getName() + ".permissionExpireThread");

                boolean started = false;

                permissionExpireThread = t;
                try
                {
                    t.start();
                    started = true;
                }
                finally
                {
                    if (!started && (permissionExpireThread == t))
                        permissionExpireThread = null;
                }
            }
        }
    }

    /**
     * Runs in {@link #PermissionExpireThread} and expires the
     * <tt>Permission</tt>s of this <tt>Allocation</tt> and removes them from
     * {@link #permissions}.
     */
    private void runInAllocationPermissionExpireThread()
    {
        try
        {
            long idleStartTime = -1;

            do
            {
                synchronized (permissions)
                {
                    try
                    {
                        permissions.wait(Permission.MAX_LIFETIME);
                    }
                    catch (InterruptedException ie)
                    {
                    }

                    /*
                     * Is the current Thread still designated to expire the
                     * Permissions of this Allocation?
                     */
                    if (Thread.currentThread() != permissionExpireThread)
                        break;

                    long now = System.currentTimeMillis();

                    /*
                     * Has the current Thread been idle long enough to merit
                     * disposing of it?
                     */
                    if (permissions.isEmpty())
                    {
                        if (idleStartTime == -1)
                            idleStartTime = now;
                        else if (now - idleStartTime > 60 * 1000)
                            break;
                    }
                    else
                    {
                        // Expire the Permissions of this Allocation.

                        idleStartTime = -1;

                        for (Iterator<Permission> i =
                            permissions.values().iterator(); i.hasNext();)
                        {
                            Permission permission = i.next();

                            if (permission == null)
                            {
                                i.remove();
                            }
                            else if (permission.isExpired(now))
                            {
                                logger.finer("Permission " + permission
                                    + " expired");
                                i.remove();
                                permission.expire();
                            }
                        }
                    }
                }
            }
            while (true);
        }
        finally
        {
            synchronized (permissions)
            {
                if (permissionExpireThread == Thread.currentThread())
                    permissionExpireThread = null;
                /*
                 * If permissionExpireThread dies unexpectedly and yet it is
                 * still necessary, resurrect it.
                 */
                if (permissionExpireThread == null)
                    maybeStartPermissionExpireThread();
            }
        }
    }

    @Override
    public int hashCode()
    {
        return this.fiveTuple.hashCode();
    }

    /**
     * Since an Allocation is uniquely identified by its relay address or five
     * tuple hence we only compare these members.
     */
    @Override
    public boolean equals(Object o)
    {
        if (!(o instanceof Allocation))
        {
            return false;
        }
        Allocation allocation = (Allocation) o;
        if (!this.fiveTuple.equals(allocation.fiveTuple))
        {
            return false;
        }
        if (!this.relayAddress.equals(allocation.relayAddress))
        {
            return false;
        }
        return true;
    }

    @Override
    public String toString()
    {
        return this.getRelayAddress().toString();
    }
 
}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/ChannelBind.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import java.util.logging.Logger;

import org.ice4j.*;

/**
 * This class is an implementation of ChannelBind in TURN protocol.
 * 
 * @author Aakash Garg
 * 
 */
public class ChannelBind
{
    /**
     * Our class logger.
     */
    private static final Logger logger = Logger.getLogger(ChannelBind.class
        .getName());
    
    /**
     * The maximum lifetime allowed for a ChannelBind (10 min).
     */
    public static final long MAX_LIFETIME = 10 * 60 * 1000;

    /**
     * The IP address and port of the peer for which to create ChannelBind.
     */
    private final TransportAddress peerAddress;

    /**
     * Represents the channel no of the ChannelBind.
     */
    private final char channelNo;
  
    /**
     * The time in milliseconds when the ChannelBinding will expire.
     */
    private long expirationTime = -1;

    /**
     * Determines whether or not the ChannelBinding has expired.
     */
    private boolean expired = true;

    /**
     * Creates a new ChannelBind object with MAX_LIFETIME as default lifetime
     * value.
     * 
     * @param peerAddress contains the peer IP address with port no and
     *            transport protocol to be assigned.
     * @param channelNo the channelNo of ChannelBind.
     */
    public ChannelBind( TransportAddress peerAddress, 
                        char channelNo)
    {
        this(peerAddress, channelNo, ChannelBind.MAX_LIFETIME);
    }

    /**
     * Creates a new ChannelBind object with given lifetime value.
     * 
     * @param peerAddress contains the peer IP address and transport protocol to
     *            be assigned. The port value is ignored.
     * @param channelNo the channelNo of the ChannelBind request.
     * @param lifetime the lifetime of ChannelBind.
     */
    public ChannelBind( TransportAddress peerAddress, 
                        char channelNo,
                        long lifetime)
    {
        this.peerAddress = peerAddress;
        if (channelNo < 0x4000)
            throw new IllegalArgumentException("Illegal value of channel no");
        this.channelNo = channelNo;
        this.setLifetime(lifetime);
    }

    /**
     * Creates a new ChannelBind object with given lifetime value and UDP as
     * default protocol.
     * 
     * @param peerAddress contains the peer IP address and port no in String
     *            format.
     * @param channelNo the channelNo of the ChannelBind.
     * @param lifetime the lifetime of ChannelBind.
     */
    public ChannelBind( String peerAddress, 
                        char channelNo, 
                        long lifetime)
    {
        this(new TransportAddress(peerAddress, 0, Transport.UDP), 
             channelNo,
             lifetime);
    }

    /**
     * @return the peerAddress as a String.
     */
    public String getPeerAddressString()
    {
        return this.getPeerAddress().getHostAddress();
    }
    
    /**
     * Returns the Peer Address associated with this ChannelBind.
     */
    public TransportAddress getPeerAddress()
    {
        return peerAddress;
    }
    
    /**
     * returns the channelNo associated with this ChannelBind.
     */
    public char getChannelNo()
    {
        return channelNo;
    }
 
    /**
     * Returns the lifetime associated with this ChannelBind.
     * If the ChannelBind is expired it returns 0. 
     */
    public long getLifetime()
    {
        if(!isExpired())
        {
            return (this.expirationTime-System.currentTimeMillis());
        }
        else
        {
            return 0;
        }
    }
    
    /**
     *  Sets the time to expire in milliseconds for this ChannelBind.
     *  Max lifetime can be ChannelBind.MAX_LIFEIME.
     *  
     *  @param lifetime the lifetime for this ChannelBind.
     */
    public void setLifetime(long lifetime)
    {
        synchronized(this)
        {
            this.expirationTime = System.currentTimeMillis()
                + Math.min(lifetime*1000, ChannelBind.MAX_LIFETIME);
        }
    }

    /**
     * Refreshes the ChannelBind with the MAX_LIFETIME value.
     */
    public void refresh()
    {
        this.setLifetime(ChannelBind.MAX_LIFETIME);
    }
    
    /**
     * refreshes the ChannelBind with given lifetime value.
     * @param lifetime the required lifetime of ChannelBind.
     */
    public void refresh(int lifetime)
    {
        this.setLifetime(lifetime);
    }
    
    /**
     * Start the ChannelBind. This launches the countdown to the moment the
     * ChannelBind would expire.
     */
    public synchronized void start()
    {
        synchronized(this)
        {
            if (expirationTime == -1)
            {
                expired = false;
                expirationTime = MAX_LIFETIME + System.currentTimeMillis();
            }
            else
            {
                throw new IllegalStateException(
                        "ChannelBind has already been started!");
            }
        }
    }
    
    /**
     * Determines whether this <tt>ChannelBind</tt> is expired now.
     *
     * @return <tt>true</tt> if this <tt>ChannelBind</tT> is expired
     * now; otherwise, <tt>false</tt>
     */
    public boolean isExpired()
    {
        return isExpired(System.currentTimeMillis());
    }
    
    /**
     * Expires the ChannelBind. Once this method is called the ChannelBind is
     * considered terminated.
     */
    public synchronized void expire()
    {
        expired = true;
        /*
         * Allocation has a background Thread running with the purpose of
         * removing expired ChannelBinds.
         */
    }
    
    /**
     * Determines whether this <tt>ChannelBind</tt> will be expired at
     * a specific point in time.
     *
     * @param now the time in milliseconds at which the <tt>expired</tt> state
     * of this <tt>ChannelBind</tt> is to be returned
     * @return <tt>true</tt> if this <tt>ChannelBind</tt> will be
     * expired at the specified point in time; otherwise, <tt>false</tt>
     */
    public synchronized boolean isExpired(long now)
    {
        if (expirationTime == -1)
            return false;
        else if (expirationTime < now)
            return true;
        else
            return expired;
    }
    
    
    @Override
    public int hashCode()
    {
        return channelNo + peerAddress.hashCode();
    }

    @Override
    public boolean equals(Object o)
    {
        if(!(o instanceof ChannelBind))
        {
            return false;
        }
        ChannelBind c = (ChannelBind) o;
        if(c.getChannelNo() == this.channelNo
                && c.getPeerAddress().equals(this.peerAddress))
        {
            return true;
        }
        return false;
    }

    @Override
    public String toString()
    {
        return "ChannelBind ["
            + (peerAddress != null ? "peerAddress=" + peerAddress + ", " : "")
            + "channelNo=" + (int)channelNo + "]";
    }
    
}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/FiveTuple.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import java.util.logging.*;
import org.ice4j.*;

/**
 * The class would represent the FiveTuple object of TURN protocol. The hashCode
 * function should be unique if possible since it will be used to uniquely find
 * the allocation object.
 * 
 * @author Aakash Garg
 */
public class FiveTuple
{
    /**
     * The <tt>Logger</tt> used by the <tt>FiveTuple</tt> class and its
     * instances for logging output.
     */
    private static final Logger logger = Logger.getLogger(FiveTuple.class
        .getName());

    /**
     * Represents the Client's Transport Address.
     */
    protected TransportAddress clientTransportAddress;

    /**
     * Represents the Server's Transport Address.
     */
    protected TransportAddress serverTransportAddress;

    /**
     * Represents the Transport Protocol.
     */
    protected Transport transport = Transport.UDP;

    /**
     * Creates a new Five tuple Object with given arguments.
     * 
     * @param clientTransportAddress The client's Address to be set
     * @param serverTransportAddress The server's Address to be set
     * @param transport The transport protocol of the client server connection.
     */
    public FiveTuple(TransportAddress clientAddress,
        TransportAddress serverAddress, Transport transport)
    {
        this.clientTransportAddress = clientAddress;
        this.serverTransportAddress = serverAddress;
        this.transport = transport;
    }

    /**
     * @return the clientTransportAddress or null if the the Client's Address
     *         has not been set.
     */
    public TransportAddress getClientTransportAddress()
    {
        return clientTransportAddress;
    }

    /**
     * @return client's port number as +ve int value or -1 if the the Client's
     *         Address has not been set.
     */
    public int getClientPortNo()
    {
        if (this.clientTransportAddress != null)
        {
            return this.clientTransportAddress.getPort();
        }
        return -1;
    }

    /**
     * @return client Host Address in String or null if the the Client's Address
     *         has not been set.
     */
    public String getClientHostAddress()
    {
        if (this.clientTransportAddress != null)
        {
            return this.clientTransportAddress.getHostAddress();
        }
        else
        {
            return null;
        }
    }

    /**
     * @param clientTransportAddress The client's IP Address to be set.
     */
    public void setClientTransportAddress(TransportAddress clientAddress)
    {
        this.clientTransportAddress = clientAddress;
    }

    /**
     * @return the serverTransportAddress or null if the the Server's Address
     *         has not been set.
     */
    public TransportAddress getServerTransportAddress()
    {
        return serverTransportAddress;
    }

    /**
     * @return server's port number as +ve int value or -1 if the the Server's
     *         Address has not been set.
     */
    public int getServerPortNo()
    {
        if (this.serverTransportAddress != null)
        {
            return this.serverTransportAddress.getPort();
        }
        else
        {
            return -1;
        }
    }

    /**
     * @return server Host Address in String or null if the the Server's Address
     *         has not been set.
     */
    public String getServerHostAddress()
    {
        if (this.serverTransportAddress != null)
        {
            return this.serverTransportAddress.getHostAddress();
        }
        else
        {
            return null;
        }
    }

    /**
     * @param serverTransportAddress The Server's Address to be set.
     */
    public void setServerTransportAddress(TransportAddress serverAddress)
    {
        this.serverTransportAddress = serverAddress;
    }

    /**
     * @return the transport protocol used for client server connection.
     */
    public Transport getTransport()
    {
        return transport;
    }

    /**
     * @param transport the transport to set.
     */
    public void setTransport(Transport transport)
    {
        this.transport = transport;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result =
            prime
                * result
                + ((clientTransportAddress == null) ? 0
                    : clientTransportAddress.hashCode());
        result =
            prime
                * result
                + ((serverTransportAddress == null) ? 0
                    : serverTransportAddress.hashCode());
        result =
            prime * result + ((transport == null) ? 0 : transport.hashCode());
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj == null)
        {
            return false;
        }
        if (!(obj instanceof FiveTuple))
        {
            return false;
        }
        FiveTuple other = (FiveTuple) obj;
        if (clientTransportAddress == null)
        {
            if (other.clientTransportAddress != null)
            {
                return false;
            }
        }
        else if (!clientTransportAddress.equals(other.clientTransportAddress))
        {
            return false;
        }
        if (serverTransportAddress == null)
        {
            if (other.serverTransportAddress != null)
            {
                return false;
            }
        }
        else if (!serverTransportAddress.equals(other.serverTransportAddress))
        {
            return false;
        }
        if (transport != other.transport)
        {
            return false;
        }
        return true;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        return "FiveTuple ["
            + (getClientTransportAddress() != null ? "getClientAddress()="
                + getClientTransportAddress() + ", " : "")
            + (getServerTransportAddress() != null ? "getServerAddress()="
                + getServerTransportAddress() + ", " : "")
            + (getTransport() != null ? "getTransport()=" + getTransport()
                + ", " : "") + "hashCode()=" + hashCode() + "]";
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/Permission.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import org.ice4j.*;

/**
 * This class is an implementation of Permissions in TURN protocol.
 * 
 * @author Aakash Garg
 * 
 */
public class Permission
{
    /**
     * The maximum lifetime allowed for a Permission.
     */
    public static final long MAX_LIFETIME = 300 * 1000;

    /**
     * The IP address of the peer for which to create Permission.
     */
    private TransportAddress ipAddress;
 /**
     * The time in milliseconds when the Permission will expire.
     */
    private long expirationTime = -1;

    /**
     * Determines whether or not the Permission has expired.
     */
    private boolean expired = false;

    /**
     * @param ipAddress contains the peer IP address and transport protocol to
     *            be assigned. The port value is ignored.
     */
    public Permission(TransportAddress ipAddress)
    {
        this.setIpAddress(ipAddress);
        this.setLifetime(Permission.MAX_LIFETIME);
    }
    
    /**
     * @param ipAddress contains the peer IP address and transport protocol to
     *            be assigned. The port value is ignored.
     * @param lifetime the lifetime of permission.
     */
    public Permission(TransportAddress ipAddress, long lifetime)
    {
        this.setIpAddress(ipAddress);
        this.setLifetime(lifetime);
    }

    /**
     * @param ipAddress contains the peer IP address in String format.
     * @param lifetime the lifetime of permission.
     */
    public Permission(String ipAddress, long lifetime)
    {
        this.setIpAddress(ipAddress);
        this.setLifetime(lifetime);
    }

    /**
     * @return the ipAddress of the Permission as a TransportAddress.
     */
    public TransportAddress getIpAddress()
    {
        return ipAddress;
    }

    /**
     * @return the ipAddress as a String.
     */
    public String getIpAddressString()
    {
        return this.getIpAddress().getHostAddress();
    }

    /**
     * @param ipAddress the ipAddress of the peer for which to create
     *            Permission.
     */
    public void setIpAddress(TransportAddress ipAddress)
    {
        this.ipAddress =
            new TransportAddress(ipAddress.getHostAddress(), 0,
                ipAddress.getTransport());
    }

    /**
     * @param ipAddress the ipAddress as String of the peer for which to create
     *            Permission.
     */
    public void setIpAddress(String ipAddress)
    {
        this.ipAddress = new TransportAddress(ipAddress, 0, Transport.UDP);
    }

    /**
     * Returns the lifetime associated with this Permission.
     * If the Permission is expired it returns 0. 
     */
    public long getLifetime()
    {
        if(!isExpired())
        {
            return (this.expirationTime-System.currentTimeMillis());
        }
        else
        {
            return 0;
        }
    }
    
    /**
     *  Sets the time to expire in milli-seconds for this Permission.
     *  Max lifetime can be Permission.MAX_LIFEIME.
     *  
     *  @param lifetime the lifetime for this Permission.
     */
    public void setLifetime(long lifetime)
    {
        synchronized(this)
        {
            this.expirationTime = System.currentTimeMillis()
                + Math.min(lifetime*1000, Permission.MAX_LIFETIME);
        }
    }
    
    /**
     * Refreshes the permission with the MAX_LIFETIME value.
     */
    public void refresh()
    {
        this.setLifetime(Permission.MAX_LIFETIME);
    }
    
    /**
     * refreshes the permission with given lifetime value.
     * @param lifetime the required lifetime of permission.
     */
    public void refresh(int lifetime)
    {
        this.setLifetime(lifetime);
    }

    /**
     * Start the Permission. This launches the countdown to the moment the
     * Permission would expire.
     */
    public synchronized void start()
    {
        synchronized(this)
        {
            if (expirationTime == -1)
            {
                expired = false;
                expirationTime = MAX_LIFETIME + System.currentTimeMillis();
            }
            else
            {
                throw new IllegalStateException(
                        "Permission has already been started!");
            }
        }
    }
    
    /**
     * Determines whether this <tt>Permission</tt> is expired now.
     *
     * @return <tt>true</tt> if this <tt>Permission</tT> is expired
     * now; otherwise, <tt>false</tt>
     */
    public boolean isExpired()
    {
        return isExpired(System.currentTimeMillis());
    }
    
    /**
     * Expires the Permission. Once this method is called the Permission is
     * considered terminated.
     */
    public synchronized void expire()
    {
        expired = true;
        /*
         * TurnStack has a background Thread running with the purpose of
         * removing expired Permissions.
         */
    }
    
    /**
     * Determines whether this <tt>Permission</tt> will be expired at
     * a specific point in time.
     *
     * @param now the time in milliseconds at which the <tt>expired</tt> state
     * of this <tt>Permission</tt> is to be returned
     * @return <tt>true</tt> if this <tt>Permission</tt> will be
     * expired at the specified point in time; otherwise, <tt>false</tt>
     */
    public synchronized boolean isExpired(long now)
    {
        if (expirationTime == -1)
            return false;
        else if (expirationTime < now)
            return true;
        else
            return expired;
    }
    /*
     * The permission is uniquely identified by its IP address, so hashCode is
     * calculated on the IP address only.
     */
    @Override
    public int hashCode()
    {
        return ipAddress.getHostAddress().hashCode();
    }

    /*
     * Two Permissions are equal if their associated IP address, lifetime and
     * transport protocol are same.
     */
    @Override
    public boolean equals(Object obj)
    {
        if (!(obj instanceof Permission))
        {
            return false;
        }
        Permission other = (Permission) obj;
        if (ipAddress == null)
        {
            if (other.ipAddress != null)
            {
                return false;
            }
        }
        else if (ipAddress.getHostAddress().compareTo(
            other.ipAddress.getHostAddress()) != 0)
        {
            return false;
        }
        if (expirationTime != other.expirationTime)
        {
            return false;
        }
        return true;
    }

    @Override
    public String toString()
    {
        return "Permission ["
            + (ipAddress != null ? "ipAddress=" + ipAddress : "") + "]";
    }
}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/ServerChannelDataEventHandler.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import java.util.Arrays;
import java.util.logging.*  ;

import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * Class to handle incoming ChannelData messages coming from Client to Server.
 * It first finds if there is a ChannelBind installed for the peer. 
 * If yes it then sends the UDP message to peer.
 * If no it then silently ignores the message.
 * 
 * @author Aakash Garg
 */
public class ServerChannelDataEventHandler implements
	ChannelDataEventHandler {
    
    /**
     * The <tt>Logger</tt> used by the
     * <tt>ServerChannelDataEventHandler</tt> class and its instances for
     * logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ServerChannelDataEventHandler.class.getName());

    /**
     * The turnStack to call.
     */
    private TurnStack turnStack;

    /**
     * Default Constructor.
     */
    public ServerChannelDataEventHandler()
    {
    }
    
    /**
     * Parametrized constructor.
     * @param turnStack the turnStack to set for this class.
     */
    public ServerChannelDataEventHandler(StunStack turnStack) 
    {
	if (turnStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) turnStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    /**
     * Sets the TurnStack for this class.
     * @param turnStack the turnStack to set for this class.
     */
    public void setTurnStack(TurnStack turnStack)
    {
	this.turnStack = turnStack;
    }
    
    /**
     * Handles the ChannelDataMessageEvent.
     * @param evt the ChannelDataMessageEvent to handle/process.
     */
    @Override
    public void handleMessageEvent(ChannelDataMessageEvent evt) 
    {
        if(!logger.isLoggable(Level.FINER)){
            logger.setLevel(Level.FINER);
        }
	ChannelData channelData = evt.getChannelDataMessage();
	char channelNo = channelData.getChannelNumber();
	byte[] data = channelData.getData();
	logger.finer("Received a ChannelData message for " + (int)channelNo
		+ " , message : " + Arrays.toString(data));
	
	TransportAddress clientAddress = evt.getRemoteAddress();
        TransportAddress serverAddress = evt.getLocalAddress();
        Transport transport = Transport.UDP;
        FiveTuple fiveTuple =
            new FiveTuple(clientAddress, serverAddress, transport);
        
        Allocation allocation 
            = this.turnStack.getServerAllocation(fiveTuple);
        
        if(allocation==null)
        {
            logger.finer("allocation not found.");
        }
        else if(!allocation.containsChannel(channelNo))
        {
	    logger.finer("ChannelNo " + (int) channelNo
		    + " not found in Allocation!");
            return;
        }
        TransportAddress destAddr = allocation.getPeerAddr(channelNo);
        if(destAddr != null)
        {
	    RawMessage message = RawMessage.build(data, data.length, destAddr,
		    allocation.getClientAddress());
	    try {
		logger.finer("Dispatching a UDP message to " + destAddr
			+ ", data: " + Arrays.toString(message.getBytes()));
		this.turnStack.sendUdpMessage(message, destAddr,
		    allocation.getRelayAddress());
	    } catch (StunException e) {
		logger.finer(e.getMessage());
	    }
        }
        else
        {
	    logger.finer("Peer address not found for channel "
		    + (int) channelNo);
        }

    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/ServerPeerUdpEventHandler.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import java.util.*;
import java.util.logging.*;

import org.ice4j.*;
import org.ice4j.message.*;
import org.ice4j.stack.*;

/**
 * Class to handle UDP messages coming from Peer. The class first checks if
 * there is a non-expired ChannelBind for the peer if yes it then sends a
 * ChannelData message to Client. If no it then finds if there is a non-expired
 * permission if yes then it sends a DataIndicatio to Client. All the mesages
 * sent to client here are from the address on which the allocation request was
 * received or the serverAddress of fiveTuple of corresponding Allocation.
 * 
 * @author Aakash Garg
 */
public class ServerPeerUdpEventHandler
    implements PeerUdpMessageEventHandler
{
    /**
     * The <tt>Logger</tt> used by the <tt>PeerUdpMessageEventHandler</tt> class
     * and its instances for logging output.
     */
    private static final Logger logger = Logger
        .getLogger(ServerPeerUdpEventHandler.class.getName());

    /**
     * The turnStack to call.
     */
    private TurnStack turnStack;

    /**
     * Default constructor.
     */
    public ServerPeerUdpEventHandler()
    {
    }

    /**
     * Parametrized constructor.
     * 
     * @param turnStack the turnStack to set for this class.
     */
    public ServerPeerUdpEventHandler(StunStack turnStack)
    {
        if (turnStack instanceof TurnStack)
        {
            this.turnStack = (TurnStack) turnStack;
        }
        else
        {
            throw new IllegalArgumentException("This is not a TurnStack!");
        }
    }

    public void setTurnStack(TurnStack turnStack)
    {
        this.turnStack = turnStack;
    }

    /**
     * Handles the PeerUdpMessageEvent.
     * 
     * @param evt the PeerUdpMessageEvent to handle/process.
     */
    @Override
    public void handleMessageEvent(PeerUdpMessageEvent evt)
    {
        if (logger.isLoggable(Level.FINER))
        {
            logger.setLevel(Level.FINEST);
            logger.finer("Received Peer UdP message message " + evt);
        }

        byte[] data = evt.getBytes();
        TransportAddress localAddress = evt.getLocalAddress();
        TransportAddress remoteAddress = evt.getRemoteAddress();
        logger.finest("Received a UDP message on: " + localAddress + ", data: "
            + byteArrayToHex(data));
        Allocation allocation =
            this.turnStack.getServerAllocation(localAddress);
        if (remoteAddress.getTransport() == Transport.TCP)
        {
            FiveTuple fiveTuple =
                new FiveTuple(remoteAddress, localAddress, Transport.TCP);
            logger.finest("Send message request from "+fiveTuple);
            if (allocation == null) // came from client
            {
                // get client allocation
                logger.finest("Message came from TCP Client");
                int connectionId =
                    this.turnStack.getConnectionIdForDataConn(fiveTuple);
                logger.finest("Connection Id extracted for "+fiveTuple+" is "+connectionId);
                allocation = this.turnStack.getAllocationFromConnectionId(connectionId);
                logger.finest("Allocation extracted is "+allocation+" for client-"+fiveTuple);
                FiveTuple peerTuple =
                    allocation.getPeerTCPConnection(connectionId);
                TransportAddress peerAddress =
                    peerTuple.getClientTransportAddress();
                TransportAddress relayAddress =
                    peerTuple.getServerTransportAddress();
                RawMessage rawMessage =
                    RawMessage.build(data, data.length, peerAddress,
                    relayAddress);
                try
                {
                    logger.finest("Relaying data to peer-" + peerAddress
                        + " from " + remoteAddress+" data-");
                    this.turnStack.sendUdpMessage(
                        rawMessage, peerAddress, relayAddress);
                }
                catch (StunException e)
                {
                    System.err.println("Unable to relay message to peer-"
                        + peerAddress + " from client-" + remoteAddress
                        + " message-" + Arrays.toString(data));
                }

            }
            else
            {
                // else came from peer
                logger.finest("Message came from TCP peer.");
                int connectionId =
                    this.turnStack.getConnectionIdForPeer(fiveTuple);
                if (!allocation.isPermitted(remoteAddress))
                {
                    logger.finest("No permission installed for peer-"+remoteAddress);
                    return;
                }
                else
                {
                    TransportAddress dataConn = allocation.getDataConnection(
                        connectionId).getClientTransportAddress();
                    if (dataConn != null)
                    {
                        RawMessage rawMessage =
                            RawMessage.build(data, data.length, dataConn,
                            allocation.getServerAddress());
                        try
                        {
                            logger.finest("Relaying data to client-" + dataConn
                                + " from peer-" + remoteAddress);
                            this.turnStack.sendUdpMessage(
                                rawMessage, dataConn,
                                allocation.getServerAddress());
                        }
                        catch (StunException e)
                        {
                            System.err
                                .println("Unable to relay message to client-"
                                    + dataConn + " from peer-" + remoteAddress
                                    + " message-" + Arrays.toString(data));
                        }
                    }else{
                        logger.finest("No data connection found for peer-"
                            + remoteAddress);
                    }
                }
            }
        }
        else if (allocation != null
            && allocation.getChannel(remoteAddress) != 0x1000)
        {
            char channelNo = allocation.getChannel(remoteAddress);
            ChannelData channelData = new ChannelData();
            channelData.setChannelNumber(channelNo);
            channelData.setData(data);
            try
            {
                logger.finest("Sending a ChannelData message " + channelData
                    + " from " + allocation.getServerAddress() + " to "
                    + allocation.getClientAddress());

                this.turnStack.sendChannelData(
                    channelData, allocation.getClientAddress(),
                    allocation.getServerAddress());
            }
            catch (StunException ex)
            {
                logger.finer(ex.getMessage());
            }
        }
        else if (allocation != null && allocation.isPermitted(remoteAddress))
        {
            TransactionID tranID = TransactionID.createNewTransactionID();
            Indication dataInd = MessageFactory.createDataIndication(
                remoteAddress, data, tranID.getBytes());
            try
            {
                logger.finest("Sending a ChannelData message " + dataInd
                    + " from " + allocation.getServerAddress() + " to "
                    + allocation.getClientAddress());

                this.turnStack.sendIndication(
                    dataInd, allocation.getClientAddress(),
                    allocation.getServerAddress());
            }
            catch (StunException e)
            {
                logger.finer(e.getMessage());
            }
        }else{
            logger
                .finest("unable to find allocation and the message is not on TCP.");
        }
    }
    
    private String byteArrayToHex(byte[] data){
        String arrayToHex= "";
        for(int i=0; i<data.length; i++){
            arrayToHex += String.format("%02X, ", data[i]); 
        }
        return arrayToHex;
    }

}


================================================
FILE: src/main/java/org/jitsi/turnserver/stack/TurnClientTransaction.java
================================================
/*
 * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the
 * Jitsi community (http://jitsi.org).
 *
 * Copyright @ 2015 Atlassian Pty Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jitsi.turnserver.stack;

import org.ice4j.ResponseCollector;
import org.ice4j.StunMessageEvent;
import org.ice4j.TransportAddress;
import org.ice4j.message.Request;
import org.ice4j.stack.*;

/**
 * {@inheritDoc}
 */
public class TurnClientTransaction
    extends StunClientTransaction
{

    /**
     * {@inheritDoc}
     */
    public TurnClientTransaction(   StunStack stackCallback, 
                                    Request request,
                                    TransportAddress requestDestination, 
                                    TransportAddress localAddress,
                                    ResponseCollector responseCollector, 
                                    TransactionID transactionID)
    {
        super(stackCallback, request, requestDestination, localAddress,
    
Download .txt
gitextract_bn5f4f2j/

├── .gitignore
├── LICENSE
├── README.md
├── build.xml
├── pom.xml
└── src/
    ├── main/
    │   ├── java/
    │   │   └── org/
    │   │       └── jitsi/
    │   │           └── turnserver/
    │   │               ├── IndicationListener.java
    │   │               ├── TurnException.java
    │   │               ├── TurnStackProperties.java
    │   │               ├── collectors/
    │   │               │   ├── AllocationResponseCollector.java
    │   │               │   ├── ChannelBindResponseCollector.java
    │   │               │   ├── ConnectResponseCollector.java
    │   │               │   ├── ConnectionBindResponseCollector.java
    │   │               │   ├── CreatePermissionResponseCollector.java
    │   │               │   └── RefreshResponseCollector.java
    │   │               ├── listeners/
    │   │               │   ├── AllocationRequestListener.java
    │   │               │   ├── BindingRequestListener.java
    │   │               │   ├── ChannelBindRequestListener.java
    │   │               │   ├── ConnectRequestListener.java
    │   │               │   ├── ConnectionAttemptIndicationListener.java
    │   │               │   ├── ConnectionBindRequestListener.java
    │   │               │   ├── CreatePermissionRequestListener.java
    │   │               │   ├── DataIndicationListener.java
    │   │               │   ├── PeerTcpConnectEventListner.java
    │   │               │   ├── RefreshRequestListener.java
    │   │               │   └── SendIndicationListener.java
    │   │               ├── socket/
    │   │               │   ├── IceTcpEventizedServerSockerWrapper.java
    │   │               │   ├── TcpConnectEvent.java
    │   │               │   ├── TcpConnectEventGenerator.java
    │   │               │   └── TcpConnectEventListener.java
    │   │               ├── stack/
    │   │               │   ├── Allocation.java
    │   │               │   ├── ChannelBind.java
    │   │               │   ├── FiveTuple.java
    │   │               │   ├── Permission.java
    │   │               │   ├── ServerChannelDataEventHandler.java
    │   │               │   ├── ServerPeerUdpEventHandler.java
    │   │               │   ├── TurnClientTransaction.java
    │   │               │   ├── TurnServer.java
    │   │               │   ├── TurnServerTransaction.java
    │   │               │   └── TurnStack.java
    │   │               └── turnClient/
    │   │                   ├── ClientChannelDataEventHandler.java
    │   │                   ├── InteractiveUdpPeer.java
    │   │                   ├── StunClient.java
    │   │                   ├── TcpPeer.java
    │   │                   ├── TurnAllocationClient.java
    │   │                   ├── TurnClient.java
    │   │                   └── TurnTcpAllocationClient.java
    │   └── resources/
    │       ├── TurnServer.propertes
    │       ├── accounts.txt
    │       └── logging.properties
    └── test/
        ├── java/
        │   └── org/
        │       └── jitsi/
        │           └── turnserver/
        │               ├── client/
        │               │   └── ClientTest.java
        │               └── stack/
        │                   └── TurnServerTestSuite.java
        └── resources/
            ├── TurnServer.propertes
            ├── accounts.txt
            └── logging.properties
Download .txt
SYMBOL INDEX (310 symbols across 43 files)

FILE: src/main/java/org/jitsi/turnserver/IndicationListener.java
  class IndicationListener (line 33) | public abstract class IndicationListener implements MessageEventHandler
    method IndicationListener (line 54) | public IndicationListener(TurnStack turnStack)
    method handleMessageEvent (line 63) | @Override
    method getTurnStack (line 85) | public TurnStack getTurnStack()
    method setLocalAddress (line 96) | public void setLocalAddress(TransportAddress localAddress)
    method handleIndication (line 110) | abstract public void handleIndication(Indication ind, Allocation alloc);
    method start (line 116) | public void start()
    method stop (line 130) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/TurnException.java
  class TurnException (line 28) | public class TurnException
    method TurnException (line 40) | public TurnException()
    method TurnException (line 47) | public TurnException(int id)
    method TurnException (line 55) | public TurnException(String message)
    method TurnException (line 64) | public TurnException(int id, String message)
    method TurnException (line 74) | public TurnException(int id, String message, Throwable cause)
    method TurnException (line 83) | public TurnException(String message, Throwable cause)
    method TurnException (line 91) | public TurnException(Throwable cause)

FILE: src/main/java/org/jitsi/turnserver/TurnStackProperties.java
  class TurnStackProperties (line 32) | public class TurnStackProperties extends StackProperties

FILE: src/main/java/org/jitsi/turnserver/collectors/AllocationResponseCollector.java
  class AllocationResponseCollector (line 36) | public class AllocationResponseCollector
    method AllocationResponseCollector (line 53) | public AllocationResponseCollector(StunStack stunStack)
    method processResponse (line 64) | @Override
    method processTimeout (line 181) | @Override

FILE: src/main/java/org/jitsi/turnserver/collectors/ChannelBindResponseCollector.java
  class ChannelBindResponseCollector (line 36) | public class ChannelBindResponseCollector
    method ChannelBindResponseCollector (line 54) | public ChannelBindResponseCollector(StunStack stunStack)
    method processResponse (line 65) | @Override
    method processTimeout (line 103) | @Override

FILE: src/main/java/org/jitsi/turnserver/collectors/ConnectResponseCollector.java
  class ConnectResponseCollector (line 35) | public class ConnectResponseCollector
    method ConnectResponseCollector (line 53) | public ConnectResponseCollector(StunStack stunStack)
    method processResponse (line 64) | @Override
    method processTimeout (line 108) | @Override

FILE: src/main/java/org/jitsi/turnserver/collectors/ConnectionBindResponseCollector.java
  class ConnectionBindResponseCollector (line 36) | public class ConnectionBindResponseCollector
    method ConnectionBindResponseCollector (line 54) | public ConnectionBindResponseCollector(StunStack stunStack)
    method processResponse (line 65) | @Override
    method processTimeout (line 100) | @Override

FILE: src/main/java/org/jitsi/turnserver/collectors/CreatePermissionResponseCollector.java
  class CreatePermissionResponseCollector (line 36) | public class CreatePermissionResponseCollector
    method CreatePermissionResponseCollector (line 54) | public CreatePermissionResponseCollector(StunStack stunStack)
    method processResponse (line 65) | @Override
    method processTimeout (line 106) | @Override

FILE: src/main/java/org/jitsi/turnserver/collectors/RefreshResponseCollector.java
  class RefreshResponseCollector (line 34) | public class RefreshResponseCollector
    method RefreshResponseCollector (line 51) | public RefreshResponseCollector(StunStack stunStack)
    method processResponse (line 62) | @Override
    method processTimeout (line 90) | @Override

FILE: src/main/java/org/jitsi/turnserver/listeners/AllocationRequestListener.java
  class AllocationRequestListener (line 36) | public class AllocationRequestListener
    method AllocationRequestListener (line 59) | public AllocationRequestListener(StunStack stunStack)
    method processRequest (line 71) | @Override
    method start (line 301) | public void start()
    method stop (line 315) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/BindingRequestListener.java
  class BindingRequestListener (line 33) | public class BindingRequestListener
    method BindingRequestListener (line 56) | public BindingRequestListener(StunStack stunStack)
    method processRequest (line 61) | @Override
    method start (line 106) | public void start()
    method stop (line 120) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/ChannelBindRequestListener.java
  class ChannelBindRequestListener (line 36) | public class ChannelBindRequestListener
    method ChannelBindRequestListener (line 60) | public ChannelBindRequestListener(StunStack turnStack)
    method processRequest (line 72) | @Override
    method start (line 187) | public void start()
    method stop (line 201) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectRequestListener.java
  class ConnectRequestListener (line 52) | public class ConnectRequestListener
    method ConnectRequestListener (line 76) | public ConnectRequestListener(StunStack stunStack)
    method processRequest (line 81) | @Override
    method start (line 198) | public void start()
    method stop (line 212) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectionAttemptIndicationListener.java
  class ConnectionAttemptIndicationListener (line 43) | public class ConnectionAttemptIndicationListener
    method ConnectionAttemptIndicationListener (line 66) | public ConnectionAttemptIndicationListener(TurnStack turnStack)
    method ConnectionAttemptIndicationListener (line 78) | public ConnectionAttemptIndicationListener(TurnStack turnStack,
    method handleIndication (line 89) | @Override

FILE: src/main/java/org/jitsi/turnserver/listeners/ConnectionBindRequestListener.java
  class ConnectionBindRequestListener (line 38) | public class ConnectionBindRequestListener
    method ConnectionBindRequestListener (line 62) | public ConnectionBindRequestListener(StunStack stunStack)
    method processRequest (line 67) | @Override
    method start (line 164) | public void start()
    method stop (line 178) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/CreatePermissionRequestListener.java
  class CreatePermissionRequestListener (line 36) | public class CreatePermissionRequestListener
    method CreatePermissionRequestListener (line 59) | public CreatePermissionRequestListener(StunStack turnStack)
    method processRequest (line 78) | @Override
    method start (line 187) | public void start()
    method stop (line 201) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/DataIndicationListener.java
  class DataIndicationListener (line 38) | public class DataIndicationListener extends IndicationListener
    method DataIndicationListener (line 53) | public DataIndicationListener(TurnStack turnStack)
    method handleIndication (line 66) | @Override

FILE: src/main/java/org/jitsi/turnserver/listeners/PeerTcpConnectEventListner.java
  class PeerTcpConnectEventListner (line 40) | public class PeerTcpConnectEventListner
    method PeerTcpConnectEventListner (line 53) | public PeerTcpConnectEventListner(TurnStack turnStack)
    method onConnect (line 58) | @Override

FILE: src/main/java/org/jitsi/turnserver/listeners/RefreshRequestListener.java
  class RefreshRequestListener (line 36) | public class RefreshRequestListener
    method RefreshRequestListener (line 59) | public RefreshRequestListener(StunStack turnStack)
    method processRequest (line 76) | @Override
    method start (line 153) | public void start()
    method stop (line 167) | public void stop()

FILE: src/main/java/org/jitsi/turnserver/listeners/SendIndicationListener.java
  class SendIndicationListener (line 38) | public class SendIndicationListener extends IndicationListener
    method SendIndicationListener (line 53) | public SendIndicationListener(TurnStack turnStack)
    method handleIndication (line 66) | @Override

FILE: src/main/java/org/jitsi/turnserver/socket/IceTcpEventizedServerSockerWrapper.java
  class IceTcpEventizedServerSockerWrapper (line 38) | public class IceTcpEventizedServerSockerWrapper
    method IceTcpEventizedServerSockerWrapper (line 77) | public IceTcpEventizedServerSockerWrapper(ServerSocket serverSocket,
    method send (line 89) | @Override
    method receive (line 99) | @Override
    method close (line 109) | @Override
    method getLocalAddress (line 129) | @Override
    method getLocalPort (line 138) | @Override
    method getLocalSocketAddress (line 147) | @Override
    method getTCPSocket (line 156) | @Override
    method getUDPSocket (line 170) | @Override
    method setEventListener (line 176) | @Override
    method removeEventListener (line 182) | @Override
    method fireConnectEvent (line 188) | @Override
    class ThreadAccept (line 201) | private class ThreadAccept
      method run (line 207) | @Override

FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEvent.java
  class TcpConnectEvent (line 30) | public class TcpConnectEvent
    method TcpConnectEvent (line 40) | public TcpConnectEvent(TransportAddress localAdress,
    method getLocalAdress (line 47) | public TransportAddress getLocalAdress()
    method getRemoteAdress (line 52) | public TransportAddress getRemoteAdress()

FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEventGenerator.java
  type TcpConnectEventGenerator (line 28) | public interface TcpConnectEventGenerator
    method setEventListener (line 30) | public void setEventListener(TcpConnectEventListener listener);
    method removeEventListener (line 32) | public void removeEventListener();
    method fireConnectEvent (line 34) | public void fireConnectEvent(TcpConnectEvent event);

FILE: src/main/java/org/jitsi/turnserver/socket/TcpConnectEventListener.java
  type TcpConnectEventListener (line 28) | public interface TcpConnectEventListener
    method onConnect (line 30) | public void onConnect(TcpConnectEvent event);

FILE: src/main/java/org/jitsi/turnserver/stack/Allocation.java
  class Allocation (line 35) | public class Allocation
    method Allocation (line 144) | public Allocation(  TransportAddress relayAddress,
    method Allocation (line 158) | public Allocation(  TransportAddress relayAddress,
    method Allocation (line 174) | public Allocation(  TransportAddress relayAddress,
    method Allocation (line 193) | public Allocation(  TransportAddress relayAddress,
    method getFiveTuple (line 209) | public FiveTuple getFiveTuple()
    method getRelayAddress (line 217) | public TransportAddress getRelayAddress()
    method getClientAddress (line 226) | public TransportAddress getClientAddress()
    method getServerAddress (line 235) | public TransportAddress getServerAddress()
    method getDataConnection (line 248) | public FiveTuple getDataConnection(int connectionId){
    method getPeerTCPConnection (line 260) | public FiveTuple getPeerTCPConnection(int connectionId){
    method addDataConnection (line 272) | public void addDataConnection(int connectionId, FiveTuple clientDataConn)
    method addPeerTCPConnection (line 286) | public void addPeerTCPConnection(int connectionId, FiveTuple peerDataC...
    method removeDataConnection (line 297) | public void removeDataConnection(int connectionId)
    method removePeerTCPConnection (line 308) | public void removePeerTCPConnection(int connectionId)
    method getLifetime (line 317) | public long getLifetime()
    method setLifetime (line 335) | public void setLifetime(long lifetime)
    method refresh (line 347) | public void refresh()
    method refresh (line 357) | public void refresh(int lifetime)
    method start (line 366) | public synchronized void start()
    method isExpired (line 389) | public boolean isExpired()
    method expire (line 398) | public synchronized void expire()
    method isExpired (line 416) | public synchronized boolean isExpired(long now)
    method addNewPermission (line 432) | public void addNewPermission(TransportAddress peerIP)
    method addNewPermission (line 445) | public void addNewPermission(Permission permission)
    method addChannelBind (line 475) | public void addChannelBind(ChannelBind channelBind)
    method isBadChannelRequest (line 521) | public boolean isBadChannelRequest(ChannelBind channelBind)
    method removeChannelBind (line 550) | public ChannelBind removeChannelBind(char channelNo)
    method isPermitted (line 568) | public boolean isPermitted(TransportAddress peerAddress)
    method containsChannel (line 588) | public boolean containsChannel(char channelNo)
    method getChannel (line 598) | public char getChannel(TransportAddress peerAddress)
    method getPeerAddr (line 616) | public TransportAddress getPeerAddr(char channelNo)
    method canHaveMorePermisions (line 632) | public boolean canHaveMorePermisions()
    method canHaveMoreChannels (line 643) | public boolean canHaveMoreChannels()
    method maybeStartChannelBindExpireThread (line 651) | public void maybeStartChannelBindExpireThread()
    method runInAllocationChannelBindExpireThread (line 691) | private void runInAllocationChannelBindExpireThread()
    method maybeStartPermissionExpireThread (line 778) | public void maybeStartPermissionExpireThread()
    method runInAllocationPermissionExpireThread (line 818) | private void runInAllocationPermissionExpireThread()
    method hashCode (line 900) | @Override
    method equals (line 910) | @Override
    method toString (line 929) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/ChannelBind.java
  class ChannelBind (line 32) | public class ChannelBind
    method ChannelBind (line 73) | public ChannelBind( TransportAddress peerAddress,
    method ChannelBind (line 87) | public ChannelBind( TransportAddress peerAddress,
    method ChannelBind (line 107) | public ChannelBind( String peerAddress,
    method getPeerAddressString (line 119) | public String getPeerAddressString()
    method getPeerAddress (line 127) | public TransportAddress getPeerAddress()
    method getChannelNo (line 135) | public char getChannelNo()
    method getLifetime (line 144) | public long getLifetime()
    method setLifetime (line 162) | public void setLifetime(long lifetime)
    method refresh (line 174) | public void refresh()
    method refresh (line 183) | public void refresh(int lifetime)
    method start (line 192) | public synchronized void start()
    method isExpired (line 215) | public boolean isExpired()
    method expire (line 224) | public synchronized void expire()
    method isExpired (line 242) | public synchronized boolean isExpired(long now)
    method hashCode (line 253) | @Override
    method equals (line 259) | @Override
    method toString (line 275) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/FiveTuple.java
  class FiveTuple (line 32) | public class FiveTuple
    method FiveTuple (line 63) | public FiveTuple(TransportAddress clientAddress,
    method getClientTransportAddress (line 75) | public TransportAddress getClientTransportAddress()
    method getClientPortNo (line 84) | public int getClientPortNo()
    method getClientHostAddress (line 97) | public String getClientHostAddress()
    method setClientTransportAddress (line 112) | public void setClientTransportAddress(TransportAddress clientAddress)
    method getServerTransportAddress (line 121) | public TransportAddress getServerTransportAddress()
    method getServerPortNo (line 130) | public int getServerPortNo()
    method getServerHostAddress (line 146) | public String getServerHostAddress()
    method setServerTransportAddress (line 161) | public void setServerTransportAddress(TransportAddress serverAddress)
    method getTransport (line 169) | public Transport getTransport()
    method setTransport (line 177) | public void setTransport(Transport transport)
    method hashCode (line 187) | @Override
    method equals (line 217) | @Override
    method toString (line 267) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/Permission.java
  class Permission (line 30) | public class Permission
    method Permission (line 55) | public Permission(TransportAddress ipAddress)
    method Permission (line 66) | public Permission(TransportAddress ipAddress, long lifetime)
    method Permission (line 76) | public Permission(String ipAddress, long lifetime)
    method getIpAddress (line 85) | public TransportAddress getIpAddress()
    method getIpAddressString (line 93) | public String getIpAddressString()
    method setIpAddress (line 102) | public void setIpAddress(TransportAddress ipAddress)
    method setIpAddress (line 113) | public void setIpAddress(String ipAddress)
    method getLifetime (line 122) | public long getLifetime()
    method setLifetime (line 140) | public void setLifetime(long lifetime)
    method refresh (line 152) | public void refresh()
    method refresh (line 161) | public void refresh(int lifetime)
    method start (line 170) | public synchronized void start()
    method isExpired (line 193) | public boolean isExpired()
    method expire (line 202) | public synchronized void expire()
    method isExpired (line 220) | public synchronized boolean isExpired(long now)
    method hashCode (line 233) | @Override
    method equals (line 243) | @Override
    method toString (line 270) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/ServerChannelDataEventHandler.java
  class ServerChannelDataEventHandler (line 37) | public class ServerChannelDataEventHandler implements
    method ServerChannelDataEventHandler (line 56) | public ServerChannelDataEventHandler()
    method ServerChannelDataEventHandler (line 64) | public ServerChannelDataEventHandler(StunStack turnStack)
    method setTurnStack (line 80) | public void setTurnStack(TurnStack turnStack)
    method handleMessageEvent (line 89) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/ServerPeerUdpEventHandler.java
  class ServerPeerUdpEventHandler (line 39) | public class ServerPeerUdpEventHandler
    method ServerPeerUdpEventHandler (line 57) | public ServerPeerUdpEventHandler()
    method ServerPeerUdpEventHandler (line 66) | public ServerPeerUdpEventHandler(StunStack turnStack)
    method setTurnStack (line 78) | public void setTurnStack(TurnStack turnStack)
    method handleMessageEvent (line 88) | @Override
    method byteArrayToHex (line 231) | private String byteArrayToHex(byte[] data){

FILE: src/main/java/org/jitsi/turnserver/stack/TurnClientTransaction.java
  class TurnClientTransaction (line 31) | public class TurnClientTransaction
    method TurnClientTransaction (line 38) | public TurnClientTransaction(   StunStack stackCallback,
    method TurnClientTransaction (line 52) | public TurnClientTransaction(   StunStack stackCallback,
    method handleResponse (line 65) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/TurnServer.java
  class TurnServer (line 37) | public class TurnServer
    method TurnServer (line 58) | public TurnServer(TransportAddress localUDPAddress)
    method main (line 75) | public static void main(String[] args) throws Exception
    method start (line 105) | public void start() throws IOException, TurnException
    method shutDown (line 177) | public void shutDown()
    method isStarted (line 193) | public boolean isStarted()
    method setBacklog (line 203) | public void setBacklog(int backlog)
    method finalize (line 208) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/TurnServerTransaction.java
  class TurnServerTransaction (line 36) | public class TurnServerTransaction
    method TurnServerTransaction (line 43) | public TurnServerTransaction(   StunStack stackCallback,
    method retransmitResponse (line 54) | @Override
    method getResponse (line 66) | @Override

FILE: src/main/java/org/jitsi/turnserver/stack/TurnStack.java
  class TurnStack (line 45) | public class TurnStack
    method TurnStack (line 147) | public TurnStack()
    method TurnStack (line 161) | public TurnStack(PeerUdpMessageEventHandler peerUdpMessageEventHandler,
    method handleMessageEvent (line 173) | @Override
    method isDontfragmentsupported (line 349) | public static boolean isDontfragmentsupported()
    method getServerAllocation (line 362) | public Allocation getServerAllocation(FiveTuple fiveTuple)
    method getClientAllocation (line 388) | public Allocation getClientAllocation(FiveTuple fiveTuple)
    method canHaveMoreAllocations (line 411) | public boolean canHaveMoreAllocations()
    method addNewServerAllocation (line 421) | public synchronized void addNewServerAllocation(Allocation allocation)
    method getServerAllocation (line 496) | public Allocation getServerAllocation(TransportAddress relayAddress)
    method isIPAllowed (line 506) | public static boolean isIPAllowed(TransportAddress peerAddr)
    method reservePort (line 520) | public boolean reservePort(TransportAddress reserAddr)
    method getNewRelayAddress (line 540) | public TransportAddress getNewRelayAddress(boolean evenCompulsary,
    method addUnAcknowlededConnectionId (line 575) | public void addUnAcknowlededConnectionId(int connectionId,
    method acknowledgeConnectionId (line 599) | public void acknowledgeConnectionId(int connectionId,
    method isUnacknowledged (line 625) | public boolean isUnacknowledged(int connectionID){
    method getConnectionIdForPeer (line 635) | public int getConnectionIdForPeer(FiveTuple peerFiveTuple)
    method getConnectionIdForDataConn (line 647) | public int getConnectionIdForDataConn(FiveTuple dataConnTuple)
    method maybeStartServerAllocationExpireThread (line 656) | public void maybeStartServerAllocationExpireThread()
    method runInServerAllocationExpireThread (line 698) | private void runInServerAllocationExpireThread()
    method isTurnMessage (line 786) | public static boolean isTurnMessage(Message message)
    method removeUsernameIntegrityFromBinding (line 822) | private void removeUsernameIntegrityFromBinding(Message msg)
    method initCredentials (line 842) | public void initCredentials()
    method getComponent (line 880) | public Component getComponent()
    method isUDPAllowed (line 897) | public boolean isUDPAllowed()
    method setUDPAllowed (line 907) | public void setUDPAllowed(boolean udpAllowed)
    method isTCPAllowed (line 917) | public boolean isTCPAllowed()
    method setTCPAllowed (line 927) | public void setTCPAllowed(boolean tcpAllowed)
    method getAllocationFromConnectionId (line 939) | public Allocation getAllocationFromConnectionId(int connectionId)

FILE: src/main/java/org/jitsi/turnserver/turnClient/ClientChannelDataEventHandler.java
  class ClientChannelDataEventHandler (line 38) | public class ClientChannelDataEventHandler implements
    method ClientChannelDataEventHandler (line 57) | public ClientChannelDataEventHandler()
    method ClientChannelDataEventHandler (line 67) | public ClientChannelDataEventHandler(StunStack turnStack)
    method setTurnStack (line 85) | public void setTurnStack(TurnStack turnStack)
    method handleMessageEvent (line 96) | @Override

FILE: src/main/java/org/jitsi/turnserver/turnClient/InteractiveUdpPeer.java
  class InteractiveUdpPeer (line 32) | public class InteractiveUdpPeer {
    method main (line 44) | public static void main(String[] args) throws IOException {
    method getRecThread (line 102) | public static Thread getRecThread()
    method getString (line 128) | public static String getString(DatagramPacket recPkt)

FILE: src/main/java/org/jitsi/turnserver/turnClient/StunClient.java
  class StunClient (line 45) | public class StunClient
    method getReport (line 50) | public static StunDiscoveryReport getReport(String... args)
    method main (line 117) | public static void main(String... args) throws Exception

FILE: src/main/java/org/jitsi/turnserver/turnClient/TcpPeer.java
  class TcpPeer (line 28) | public class TcpPeer
    method main (line 31) | public static void main(String... args)
    method byteArrayToHex (line 63) | private static String byteArrayToHex(byte[] data)
    method main2 (line 73) | public static void main2(String[] args)

FILE: src/main/java/org/jitsi/turnserver/turnClient/TurnAllocationClient.java
  class TurnAllocationClient (line 41) | public class TurnAllocationClient
    method main (line 68) | public static void main(String[] args) throws IOException, StunException,
    method sendAllocationRequest (line 104) | public static StunMessageEvent sendAllocationRequest(
    method sendCreatePermissionRequest (line 145) | public static StunMessageEvent sendCreatePermissionRequest(int peerPort)
    method sendChannelBindRequest (line 184) | public static StunMessageEvent sendChannelBindRequest(
    method sendChannelDataMessage (line 249) | public static void sendChannelDataMessage() throws StunException,
    method start (line 265) | public static void start()
    method doInteractiveComm (line 287) | public static void doInteractiveComm() throws IOException, StunException
    method shutDown (line 315) | public static void shutDown()

FILE: src/main/java/org/jitsi/turnserver/turnClient/TurnClient.java
  class TurnClient (line 48) | public class TurnClient
    method getReport (line 53) | public static StunDiscoveryReport getReport(String... args)
    method main (line 123) | public static void main(String... args) throws Exception

FILE: src/main/java/org/jitsi/turnserver/turnClient/TurnTcpAllocationClient.java
  class TurnTcpAllocationClient (line 41) | public class TurnTcpAllocationClient
    method start (line 69) | public static void start(Transport protocol) throws IOException,
    method main (line 105) | public static void main(String[] args) throws IOException, StunException,
    method sendAllocationRequest (line 138) | public static StunMessageEvent sendAllocationRequest(
    method sendCreatePermissionRequest (line 181) | public static StunMessageEvent sendCreatePermissionRequest(int peerPort)
    method sendConnectRequest (line 217) | public static StunMessageEvent sendConnectRequest(int peerPort)
    method doInteractiveComm (line 254) | public static void doInteractiveComm() throws IOException, StunException
    method shutDown (line 278) | public static void shutDown()

FILE: src/test/java/org/jitsi/turnserver/client/ClientTest.java
  class ClientTest (line 44) | public class ClientTest
    method setUp (line 60) | @Before
    method tearDown (line 102) | @After
    method testUDPClient (line 111) | @Test
    method testIceMediaStream (line 131) | @Test
    method getLocalAddress (line 150) | private String getLocalAddress()
    class ControlClient (line 190) | class ControlClient implements Runnable
      method run (line 193) | public void run()
    class EndpointClient (line 282) | class EndpointClient implements Runnable
      method run (line 285) | public void run()

FILE: src/test/java/org/jitsi/turnserver/stack/TurnServerTestSuite.java
  class TurnServerTestSuite (line 31) | @RunWith(Suite.class)
Condensed preview — 54 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (311K chars).
[
  {
    "path": ".gitignore",
    "chars": 48,
    "preview": ".idea\nbin\n.project\n.classpath\n.settings\ntarget/\n"
  },
  {
    "path": "LICENSE",
    "chars": 11358,
    "preview": "\n                                 Apache License\n                           Version 2.0, January 2004\n                  "
  },
  {
    "path": "README.md",
    "chars": 680,
    "preview": "turnserver\n==========\n\nWelcome to the TurnServer project - open-source TURN server implementation.\n\nThe TURN protocol al"
  },
  {
    "path": "build.xml",
    "chars": 5643,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<project name=\"turnserver\" basedir=\".\" default=\"rebuild\">\n\t<property name=\"dest\""
  },
  {
    "path": "pom.xml",
    "chars": 2293,
    "preview": "<project\n    xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/IndicationListener.java",
    "chars": 3663,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/TurnException.java",
    "chars": 1866,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/TurnStackProperties.java",
    "chars": 3025,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/AllocationResponseCollector.java",
    "chars": 6096,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ChannelBindResponseCollector.java",
    "chars": 3082,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ConnectResponseCollector.java",
    "chars": 3369,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/ConnectionBindResponseCollector.java",
    "chars": 2957,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/CreatePermissionResponseCollector.java",
    "chars": 3265,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/collectors/RefreshResponseCollector.java",
    "chars": 2458,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/AllocationRequestListener.java",
    "chars": 12414,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/BindingRequestListener.java",
    "chars": 3929,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ChannelBindRequestListener.java",
    "chars": 6910,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectRequestListener.java",
    "chars": 7823,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectionAttemptIndicationListener.java",
    "chars": 8145,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/ConnectionBindRequestListener.java",
    "chars": 6115,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/CreatePermissionRequestListener.java",
    "chars": 7175,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/DataIndicationListener.java",
    "chars": 2799,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/PeerTcpConnectEventListner.java",
    "chars": 3756,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/RefreshRequestListener.java",
    "chars": 5508,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/listeners/SendIndicationListener.java",
    "chars": 2939,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/IceTcpEventizedServerSockerWrapper.java",
    "chars": 6751,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEvent.java",
    "chars": 1481,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEventGenerator.java",
    "chars": 1087,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/socket/TcpConnectEventListener.java",
    "chars": 951,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/Allocation.java",
    "chars": 29146,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ChannelBind.java",
    "chars": 7720,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/FiveTuple.java",
    "chars": 7377,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/Permission.java",
    "chars": 7404,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ServerChannelDataEventHandler.java",
    "chars": 4197,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/ServerPeerUdpEventHandler.java",
    "chars": 8940,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnClientTransaction.java",
    "chars": 2246,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnServer.java",
    "chars": 7065,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnServerTransaction.java",
    "chars": 1908,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/stack/TurnStack.java",
    "chars": 30535,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/ClientChannelDataEventHandler.java",
    "chars": 3152,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/InteractiveUdpPeer.java",
    "chars": 3936,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/StunClient.java",
    "chars": 4594,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TcpPeer.java",
    "chars": 2779,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnAllocationClient.java",
    "chars": 11782,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnClient.java",
    "chars": 4786,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/java/org/jitsi/turnserver/turnClient/TurnTcpAllocationClient.java",
    "chars": 10016,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/main/resources/TurnServer.propertes",
    "chars": 663,
    "preview": "org.jitsi.turnserver.udp_port = 3478;\norg.jitsi.turnserver.max_port = 65535;\norg.jitsi.turnserver.min_port = 49152;\norg."
  },
  {
    "path": "src/main/resources/accounts.txt",
    "chars": 99,
    "preview": "JitsiGsocStudent:8156CE4E8499609C34C641E2C2904171\nJitsiGsocMentor:654714090BC4348274203EE55EEFBB26\n"
  },
  {
    "path": "src/main/resources/logging.properties",
    "chars": 2174,
    "preview": "############################################################\n#  Default Logging Configuration File\n#\n# You can use a dif"
  },
  {
    "path": "src/test/java/org/jitsi/turnserver/client/ClientTest.java",
    "chars": 13002,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/test/java/org/jitsi/turnserver/stack/TurnServerTestSuite.java",
    "chars": 1057,
    "preview": "/*\n * TurnServer, the OpenSource Java Solution for TURN protocol. Maintained by the\n * Jitsi community (http://jitsi.org"
  },
  {
    "path": "src/test/resources/TurnServer.propertes",
    "chars": 665,
    "preview": "org.jitsi.turnserver.udp_port = 3478;\norg.jitsi.turnserver.max_port = 65535;\norg.jitsi.turnserver.min_port = 49152;\norg."
  },
  {
    "path": "src/test/resources/accounts.txt",
    "chars": 100,
    "preview": "JitsiGsocStudent:8156CE4E8499609C34C641E2C2904171\nJitsiGsocMentor:654714090BC4348274203EE55EEFBB26\n\n"
  },
  {
    "path": "src/test/resources/logging.properties",
    "chars": 2084,
    "preview": "############################################################\n#  Default Logging Configuration File\n#\n# You can use a dif"
  }
]

About this extraction

This page contains the full source code of the jitsi/turnserver GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 54 files (288.1 KB), approximately 61.9k tokens, and a symbol index with 310 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!