/*
* 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 + "]";
}
}