/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.STUN_ADDRESS;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.STUN_IS_TURN_SUPPORTED;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.STUN_PASSWORD;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.STUN_PORT;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.STUN_USERNAME;
import java.io.*;
import java.util.*;
import org.jitsi.util.*;
/**
* A StunServerDescriptor stores information necessary to create a
* STUN or TURN candidate harvester that we could use with ICE4J. Descriptors
* are normally initialized by protocol wizards. They are then used to convert
* the data into a {@link String} form suitable for storage in an accounts
* properties Map.
*
* @author Yana Stamcheva
* @author Emil Ivov
*/
public class StunServerDescriptor
implements Serializable
{
/**
* The maximum number of stun servers that we would allow.
*/
public static final int MAX_STUN_SERVER_COUNT = 100;
/**
* UDP protocol.
*/
public static final String PROTOCOL_UDP = "udp";
/**
* TCP protocol.
*/
public static final String PROTOCOL_TCP = "tcp";
/**
* TCP with SSL protocol (only for Google Talk TURN server).
*/
public static final String PROTOCOL_SSLTCP = "ssltcp";
/**
* The address (IP or FQDN) of the server.
*/
private String address;
/**
* The port of the server.
*/
private int port;
/**
* Indicates if the server can also act as a TURN server (as opposed to a
* STUN only server).
*/
private boolean isTurnSupported;
/**
* If TURN version supported by this StunServerDescriptor is not
* the RFC 5766.
*/
private boolean isOldTurn = false;
/**
* The username that we need to use with the server or null if
* this server does not require a user name.
*/
private byte[] username;
/**
* The password that we need to use when authenticating with the server
* or null if no password is necessary.
*/
private byte[] password;
/**
* Transport protocol used.
*/
private String protocol = PROTOCOL_UDP;
/**
* Creates an instance of StunServer by specifying all parameters.
*
* @param address the IP address or FQDN of the STUN server
* @param port the port of the server
* @param supportTurn indicates if this STUN server supports TURN
* @param username the user name for authenticating
* @param password the password
*/
public StunServerDescriptor( String address,
int port,
boolean supportTurn,
String username,
String password)
{
this.address = address;
this.port = port;
this.isTurnSupported = supportTurn;
this.username = (username != null) ? StringUtils.getUTF8Bytes(username)
: "".getBytes();
this.password = (password != null) ? StringUtils.getUTF8Bytes(password)
: "".getBytes();
}
/**
* Returns the IP address or FQDN of this server.
*
* @return the IP address or FQDN of this server
*/
public String getAddress()
{
return address;
}
/**
* Sets the IP address or FQDN of this server.
*
* @param address the IP address or FQDN to set
*/
public void setAddress(String address)
{
this.address = address;
}
/**
* Returns the port of this server.
*
* @return the port of this server
*/
public int getPort()
{
return port;
}
/**
* Sets the port corresponding to this server.
*
* @param port the port to set
*/
public void setPort(int port)
{
this.port = port;
}
/**
* Indicates if TURN is supported by this server.
*
* @return true if TURN is supported by this server, otherwise -
* returns false
*/
public boolean isTurnSupported()
{
return isTurnSupported;
}
/**
* Specifies whether this server can also act as a TURN relay.
*
* @param turnSupported true to indicate that TURN is supported,
* false - otherwise
*/
public void setTurnSupported(boolean turnSupported)
{
this.isTurnSupported = turnSupported;
}
/**
* Returns the username associated to this server.
*
* @return the username associated to this server
*/
public byte[] getUsername()
{
return username;
}
/**
* Sets the username associated to this server.
*
* @param username the username to set
*/
public void setUsername(String username)
{
this.username = StringUtils.getUTF8Bytes(username);
}
/**
* Returns the password associated to this server username.
*
* @return the password associated to this server username
*/
public byte[] getPassword()
{
return password;
}
/**
* Sets the password associated to this server username.
*
* @param password the password to set
*/
public void setPassword(String password)
{
this.password = StringUtils.getUTF8Bytes(password);
}
/**
* Stores this descriptor into the specified {@link Map}.The method is meant
* for use with account property maps. It also allows prepending an account
* prefix to all property names so that multiple descriptors can be stored
* in a single {@link Map}.
*
* @param props the account properties {@link Map} that we'd like to store
* this descriptor in.
* @param namePrefix the prefix that we should prepend to every property
* name.
*/
public void storeDescriptor(Map props, String namePrefix)
{
if(namePrefix == null)
namePrefix = "";
props.put(namePrefix + STUN_ADDRESS, getAddress());
if(getPort() != -1)
props.put(namePrefix + STUN_PORT, Integer.toString( getPort() ));
if (getUsername() != null && getUsername().length > 0)
props.put(namePrefix + STUN_USERNAME,
StringUtils.getUTF8String(getUsername()));
if (getPassword() != null && getPassword().length > 0)
{
//props.put(namePrefix + STUN_PASSWORD, new String(getPassword()));
props.put(namePrefix + "." + STUN_PASSWORD,
new String(getPassword()));
}
props.put(namePrefix + STUN_IS_TURN_SUPPORTED,
Boolean.toString( isTurnSupported() ));
}
/**
* Loads this descriptor from the specified {@link Map}.The method is meant
* for use with account property maps. It also allows prepending an account
* prefix to all property names so that multiple descriptors can be read
* in a single {@link Map}.
*
* @param props the account properties {@link Map} that we'd like to load
* this descriptor from.
* @param namePrefix the prefix that we should prepend to every property
* name.
*
* @return the newly created descriptor or null if no descriptor was found.
*/
public static StunServerDescriptor loadDescriptor(
Map props,
String namePrefix)
{
if(namePrefix == null)
namePrefix = "";
String stunAddress = props.get(namePrefix + STUN_ADDRESS);
// there doesn't seem to be a stun server with the specified prefix
if (stunAddress == null)
return null;
String stunPortStr = props.get(namePrefix + STUN_PORT);
int stunPort = -1;
try
{
stunPort = Integer.parseInt(stunPortStr);
}
catch(Throwable t)
{
//if the port value was wrong we just keep the default: -1
}
String stunUsername = props.get(namePrefix + STUN_USERNAME);
String stunPassword = props.get(namePrefix + STUN_PASSWORD);
boolean stunIsTurnSupported
= Boolean.parseBoolean(
props.get(namePrefix + STUN_IS_TURN_SUPPORTED));
StunServerDescriptor stunServer =
new StunServerDescriptor( stunAddress,
stunPort,
stunIsTurnSupported,
stunUsername,
stunPassword);
return stunServer;
}
/**
* Returns true if the TURN protocol supported is not the RFC5766 ones.
*
* @return Returns true if the TURN protocol supported is not the RFC5766
* ones.
*/
public boolean isOldTurn()
{
return isOldTurn;
}
/**
* Set the old TURN support.
*
* @param val value to set
*/
public void setOldTurn(boolean val)
{
this.isOldTurn = val;
}
/**
* Returns the protocol associated to this server.
*
* @return the protocol associated to this server
*/
public String getProtocol()
{
return protocol;
}
/**
* Sets the protocol associated to this server.
*
* @param protocol protocol to set
*/
public void setProtocol(String protocol)
{
this.protocol = protocol;
}
/**
* Returns a String representation of this descriptor
*
* @return a String representation of this descriptor.
*/
@Override
public String toString()
{
return "StunServerDesc: " + getAddress() + "/"
+ getPort()
+ " turnSupp=" + this.isTurnSupported();
}
}