mirror of https://github.com/sipwise/jitsi.git
parent
d016f4fd6d
commit
f5b574a71a
Binary file not shown.
Binary file not shown.
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.jabber;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
import org.ice4j.*;
|
||||
import org.ice4j.ice.*;
|
||||
import org.ice4j.socket.*;
|
||||
|
||||
/**
|
||||
* Represents a <tt>Candidate</tt> obtained via Jingle Nodes.
|
||||
*
|
||||
* @author Sebastien Vincent
|
||||
*/
|
||||
public class JingleNodesCandidate
|
||||
extends LocalCandidate
|
||||
{
|
||||
/**
|
||||
* The socket used to communicate with relay.
|
||||
*/
|
||||
private DatagramSocket socket = null;
|
||||
|
||||
/**
|
||||
* The <tt>RelayedCandidateDatagramSocket</tt> of this
|
||||
* <tt>JingleNodesCandidate</tt>.
|
||||
*/
|
||||
private JingleNodesCandidateDatagramSocket
|
||||
jingleNodesCandidateDatagramSocket = null;
|
||||
|
||||
/**
|
||||
* <tt>TransportAddress</tt> of the Jingle Nodes relay where we will send
|
||||
* our packet.
|
||||
*/
|
||||
private TransportAddress localEndPoint = null;
|
||||
|
||||
/**
|
||||
* Creates a <tt>JingleNodesRelayedCandidate</tt> for the specified
|
||||
* transport, address, and base.
|
||||
*
|
||||
* @param transportAddress the transport address that this candidate is
|
||||
* encapsulating.
|
||||
* @param parentComponent the <tt>Component</tt> that this candidate
|
||||
* belongs to.
|
||||
* @param localEndPoint <tt>TransportAddress</tt> of the Jingle Nodes relay
|
||||
* where we will send our packet.
|
||||
*/
|
||||
public JingleNodesCandidate(TransportAddress transportAddress,
|
||||
Component parentComponent, TransportAddress localEndPoint)
|
||||
{
|
||||
super(transportAddress, parentComponent,
|
||||
CandidateType.RELAYED_CANDIDATE);
|
||||
setBase(this);
|
||||
setRelayServerAddress(localEndPoint);
|
||||
this.localEndPoint = localEndPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <tt>JingleNodesCandidateDatagramSocket</tt> of this
|
||||
* <tt>JingleNodesCandidate</tt>.
|
||||
* <p>
|
||||
* <b>Note</b>: The method is part of the internal API of
|
||||
* <tt>RelayedCandidate</tt> and <tt>TurnCandidateHarvest</tt> and is not
|
||||
* intended for public use.
|
||||
* </p>
|
||||
*
|
||||
* @return the <tt>RelayedCandidateDatagramSocket</tt> of this
|
||||
* <tt>RelayedCandidate</tt>
|
||||
*/
|
||||
public synchronized JingleNodesCandidateDatagramSocket
|
||||
getRelayedCandidateDatagramSocket()
|
||||
{
|
||||
if (jingleNodesCandidateDatagramSocket == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
jingleNodesCandidateDatagramSocket
|
||||
= new JingleNodesCandidateDatagramSocket(
|
||||
this, localEndPoint);
|
||||
}
|
||||
catch (SocketException sex)
|
||||
{
|
||||
throw new UndeclaredThrowableException(sex);
|
||||
}
|
||||
}
|
||||
return jingleNodesCandidateDatagramSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the <tt>DatagramSocket</tt> associated with this <tt>Candidate</tt>.
|
||||
*
|
||||
* @return the <tt>DatagramSocket</tt> associated with this
|
||||
* <tt>Candidate</tt>
|
||||
*/
|
||||
public DatagramSocket getSocket()
|
||||
{
|
||||
if (socket == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket
|
||||
= new MultiplexingDatagramSocket(
|
||||
getRelayedCandidateDatagramSocket());
|
||||
}
|
||||
catch (SocketException sex)
|
||||
{
|
||||
throw new UndeclaredThrowableException(sex);
|
||||
}
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.jabber;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
|
||||
import org.ice4j.*;
|
||||
|
||||
/**
|
||||
* Represents an application-purposed (as opposed to an ICE-specific)
|
||||
* <tt>DatagramSocket</tt> for a <tt>JingleNodesCandidate</tt>.
|
||||
*
|
||||
* @author Sebastien Vincent
|
||||
*/
|
||||
public class JingleNodesCandidateDatagramSocket extends DatagramSocket
|
||||
{
|
||||
/**
|
||||
* <tt>TransportAddress</tt> of the Jingle Nodes relay where we will send
|
||||
* our packet.
|
||||
*/
|
||||
private TransportAddress localEndPoint = null;
|
||||
|
||||
/**
|
||||
* The <tt>JingleNodesCandidate</tt>.
|
||||
*/
|
||||
private JingleNodesCandidate jingleNodesCandidate;
|
||||
|
||||
/**
|
||||
* Initializes a new <tt>JingleNodesdCandidateDatagramSocket</tt> instance
|
||||
* which is to be the <tt>socket</tt> of a specific
|
||||
* <tt>JingleNodesCandidate</tt>.
|
||||
*
|
||||
* @param jingleNodesCandidate the <tt>JingleNodesCandidate</tt> which is to
|
||||
* use the new instance as the value of its <tt>socket</tt> property
|
||||
* @param localEndPoint <tt>TransportAddress</tt> of the Jingle Nodes relay
|
||||
* where we will send our packet.
|
||||
* @throws SocketException if anything goes wrong while initializing the new
|
||||
* <tt>JingleNodesCandidateDatagramSocket</tt> instance
|
||||
*/
|
||||
public JingleNodesCandidateDatagramSocket(
|
||||
JingleNodesCandidate jingleNodesCandidate,
|
||||
TransportAddress localEndPoint)
|
||||
throws SocketException
|
||||
{
|
||||
super(/* bindaddr */ (SocketAddress) null);
|
||||
this.jingleNodesCandidate = jingleNodesCandidate;
|
||||
this.localEndPoint = localEndPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a datagram packet from this socket. The <tt>DatagramPacket</tt>
|
||||
* includes information indicating the data to be sent, its length, the IP
|
||||
* address of the remote host, and the port number on the remote host.
|
||||
*
|
||||
* @param p the <tt>DatagramPacket</tt> to be sent
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @see DatagramSocket#send(DatagramPacket)
|
||||
*/
|
||||
@Override
|
||||
public void send(DatagramPacket p)
|
||||
throws IOException
|
||||
{
|
||||
byte data[] = p.getData();
|
||||
int dataLen = p.getLength();
|
||||
int dataOffset = p.getOffset();
|
||||
|
||||
/* send to Jingle Nodes relay address on local port */
|
||||
DatagramPacket packet = new DatagramPacket(data, dataOffset, dataLen,
|
||||
new InetSocketAddress(localEndPoint.getAddress(),
|
||||
localEndPoint.getPort()));
|
||||
|
||||
//XXX reuse an existing DatagramPacket ?
|
||||
super.send(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the local address to which the socket is bound.
|
||||
* <tt>JingleNodesCandidateDatagramSocket</tt> returns the <tt>address</tt>
|
||||
* of its <tt>localSocketAddress</tt>.
|
||||
* <p>
|
||||
* If there is a security manager, its <tt>checkConnect</tt> method is first
|
||||
* called with the host address and <tt>-1</tt> as its arguments to see if
|
||||
* the operation is allowed.
|
||||
* </p>
|
||||
*
|
||||
* @return the local address to which the socket is bound, or an
|
||||
* <tt>InetAddress</tt> representing any local address if either the socket
|
||||
* is not bound, or the security manager <tt>checkConnect</tt> method does
|
||||
* not allow the operation
|
||||
* @see #getLocalSocketAddress()
|
||||
* @see DatagramSocket#getLocalAddress()
|
||||
*/
|
||||
@Override
|
||||
public InetAddress getLocalAddress()
|
||||
{
|
||||
return getLocalSocketAddress().getAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port number on the local host to which this socket is bound.
|
||||
* <tt>JingleNodesCandidateDatagramSocket</tt> returns the <tt>port</tt> of
|
||||
* its <tt>localSocketAddress</tt>.
|
||||
*
|
||||
* @return the port number on the local host to which this socket is bound
|
||||
* @see #getLocalSocketAddress()
|
||||
* @see DatagramSocket#getLocalPort()
|
||||
*/
|
||||
@Override
|
||||
public int getLocalPort()
|
||||
{
|
||||
return getLocalSocketAddress().getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the endpoint this socket is bound to, or
|
||||
* <tt>null</tt> if it is not bound yet. Since
|
||||
* <tt>JingleNodesCandidateDatagramSocket</tt> represents an
|
||||
* application-purposed <tt>DatagramSocket</tt> relaying data to and from a
|
||||
* Jingle Nodes relay, the <tt>localSocketAddress</tt> is the
|
||||
* <tt>transportAddress</tt> of respective <tt>JingleNodesCandidate</tt>.
|
||||
*
|
||||
* @return a <tt>SocketAddress</tt> representing the local endpoint of this
|
||||
* socket, or <tt>null</tt> if it is not bound yet
|
||||
* @see DatagramSocket#getLocalSocketAddress()
|
||||
*/
|
||||
@Override
|
||||
public InetSocketAddress getLocalSocketAddress()
|
||||
{
|
||||
return jingleNodesCandidate.getTransportAddress();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.jabber;
|
||||
|
||||
import java.net.DatagramSocket;
|
||||
import java.util.*;
|
||||
|
||||
import org.ice4j.*;
|
||||
import org.ice4j.ice.*;
|
||||
import org.ice4j.ice.harvest.*;
|
||||
|
||||
import org.jivesoftware.smack.*;
|
||||
import org.xmpp.jnodes.smack.*;
|
||||
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Implements a <tt>CandidateHarvester</tt> which gathers <tt>Candidate</tt>s
|
||||
* for a specified {@link Component} using Jingle Nodes as defined in
|
||||
* XEP 278 "Jingle Relay Nodes".
|
||||
*
|
||||
* @author Sebastien Vincent
|
||||
*/
|
||||
public class JingleNodesHarvester
|
||||
implements CandidateHarvester
|
||||
{
|
||||
/**
|
||||
* The <tt>Logger</tt> used by the <tt>JingleNodesHarvester</tt> class and
|
||||
* its instances for logging output.
|
||||
*/
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(JingleNodesHarvester.class.getName());
|
||||
|
||||
/**
|
||||
* XMPP connection.
|
||||
*/
|
||||
private SmackServiceNode serviceNode = null;
|
||||
|
||||
/**
|
||||
* JingleNodes relay allocate two address/port couple for us. Due to the
|
||||
* architecture of Ice4j that harvest address for each component, we store
|
||||
* the second address/port couple.
|
||||
*/
|
||||
private TransportAddress localAddressSecond = null;
|
||||
|
||||
/**
|
||||
* JingleNodes relay allocate two address/port couple for us. Due to the
|
||||
* architecture of Ice4j that harvest address for each component, we store
|
||||
* the second address/port couple.
|
||||
*/
|
||||
private TransportAddress relayedAddressSecond = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param serviceNode the <tt>SmackServiceNode</tt>
|
||||
*/
|
||||
public JingleNodesHarvester(SmackServiceNode serviceNode)
|
||||
{
|
||||
this.serviceNode = serviceNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers Jingle Nodes candidates for all host <tt>Candidate</tt>s that are
|
||||
* already present in the specified <tt>component</tt>. This method relies
|
||||
* on the specified <tt>component</tt> to already contain all its host
|
||||
* candidates so that it would resolve them.
|
||||
*
|
||||
* @param component the {@link Component} that we'd like to gather candidate
|
||||
* Jingle Nodes <tt>Candidate</tt>s for
|
||||
* @return the <tt>LocalCandidate</tt>s gathered by this
|
||||
* <tt>CandidateHarvester</tt>
|
||||
*/
|
||||
public synchronized Collection<LocalCandidate> harvest(Component component)
|
||||
{
|
||||
logger.info("harvest Jingle Nodes");
|
||||
|
||||
Collection<LocalCandidate> candidates = new HashSet<LocalCandidate>();
|
||||
String ip = null;
|
||||
int port = -1;
|
||||
|
||||
/* if we have already a candidate (RTCP) allocated, get it */
|
||||
if(localAddressSecond != null && relayedAddressSecond != null)
|
||||
{
|
||||
LocalCandidate candidate = createJingleNodesCandidate(
|
||||
relayedAddressSecond, component, localAddressSecond);
|
||||
candidates.add(candidate);
|
||||
component.addLocalCandidate(candidate);
|
||||
|
||||
localAddressSecond = null;
|
||||
relayedAddressSecond = null;
|
||||
return candidates;
|
||||
}
|
||||
|
||||
XMPPConnection conn = serviceNode.getConnection();
|
||||
JingleChannelIQ ciq = null;
|
||||
|
||||
if (serviceNode != null)
|
||||
{
|
||||
final TrackerEntry preferred = serviceNode.getPreferedRelay();
|
||||
|
||||
if (preferred != null)
|
||||
{
|
||||
ciq = SmackServiceNode.getChannel(conn, preferred.getJid());
|
||||
}
|
||||
}
|
||||
|
||||
if (ciq != null && ciq.getRemoteport() > 0)
|
||||
{
|
||||
ip = ciq.getHost();
|
||||
port = ciq.getRemoteport();
|
||||
|
||||
if(logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("JN relay: " + ip + " remote port:" + port +
|
||||
" local port: " + ciq.getLocalport());
|
||||
}
|
||||
|
||||
/* RTP */
|
||||
TransportAddress relayedAddress = new TransportAddress(ip, port,
|
||||
Transport.UDP);
|
||||
TransportAddress localAddress = new TransportAddress(ip,
|
||||
ciq.getLocalport(), Transport.UDP);
|
||||
|
||||
LocalCandidate local = createJingleNodesCandidate(
|
||||
relayedAddress, component, localAddress);
|
||||
|
||||
/* RTCP */
|
||||
relayedAddressSecond
|
||||
= new TransportAddress(ip, port + 1,Transport.UDP);
|
||||
localAddressSecond
|
||||
= new TransportAddress(ip, ciq.getLocalport() + 1,
|
||||
Transport.UDP);
|
||||
|
||||
candidates.add(local);
|
||||
component.addLocalCandidate(local);
|
||||
}
|
||||
return candidates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <tt>JingleNodesRelayedCandidate</tt> instance which is to
|
||||
* represent a specific <tt>TransportAddress</tt>.
|
||||
*
|
||||
* @param transportAddress the <tt>TransportAddress</tt> allocated by the
|
||||
* relay
|
||||
* @param component the <tt>Component</tt> for which the candidate will be
|
||||
* added
|
||||
* @param localEndPoint <tt>TransportAddress</tt> of the Jingle Nodes relay
|
||||
* where we will send our packet.
|
||||
* @return a new <tt>JingleNodesRelayedCandidate</tt> instance which
|
||||
* represents the specified <tt>TransportAddress</tt>
|
||||
*/
|
||||
protected JingleNodesCandidate createJingleNodesCandidate(
|
||||
TransportAddress transportAddress, Component component,
|
||||
TransportAddress localEndPoint)
|
||||
{
|
||||
JingleNodesCandidate cand = null;
|
||||
|
||||
try
|
||||
{
|
||||
cand = new JingleNodesCandidate(transportAddress,
|
||||
component,
|
||||
localEndPoint);
|
||||
DatagramSocket stunSocket = cand.getStunSocket(null);
|
||||
cand.getStunStack().addSocket(stunSocket);
|
||||
}
|
||||
catch(Throwable e)
|
||||
{
|
||||
logger.debug(
|
||||
"Exception occurred when creating JingleNodesCandidate: " +
|
||||
e);
|
||||
}
|
||||
|
||||
return cand;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* SIP Communicator, 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 java.util.*;
|
||||
|
||||
/**
|
||||
* A <tt>JingleNodesDescriptor</tt> stores information necessary to create a
|
||||
* JingleNodes tracker or relay 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
|
||||
* @author Sebastien Vincent
|
||||
*/
|
||||
public class JingleNodeDescriptor
|
||||
{
|
||||
/**
|
||||
* JingleNodes prefix to store configuration.
|
||||
*/
|
||||
public static final String JN_PREFIX = "JINGLENODES";
|
||||
|
||||
/**
|
||||
* JingleNodes prefix to store server address in configuration.
|
||||
*/
|
||||
public static final String JN_ADDRESS = "ADDRESS";
|
||||
|
||||
/**
|
||||
* JingleNodes prefix to store the relay capabilities in configuration.
|
||||
*/
|
||||
public static final String JN_IS_RELAY_SUPPORTED = "IS_RELAY_SUPPORTED";
|
||||
|
||||
/**
|
||||
* The maximum number of stun servers that we would allow.
|
||||
*/
|
||||
public static final int MAX_JN_RELAY_COUNT = 100;
|
||||
|
||||
/**
|
||||
* The address of the JingleNodes (JID).
|
||||
*/
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* If the relay is supported by this JingleNodes.
|
||||
*/
|
||||
private boolean relaySupported;
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>JingleNodes</tt> by specifying all
|
||||
* parameters.
|
||||
*
|
||||
* @param address address of the JingleNodes
|
||||
* @param relaySupported if the JingleNodes supports relay
|
||||
*/
|
||||
public JingleNodeDescriptor(String address,
|
||||
boolean relaySupported)
|
||||
{
|
||||
this.address = address;
|
||||
this.relaySupported = relaySupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the JingleNodes
|
||||
*
|
||||
* @return the address of the JingleNodes
|
||||
*/
|
||||
public String getJID()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the address of the JingleNodes.
|
||||
*
|
||||
* @param address the JID of the JingleNodes
|
||||
*/
|
||||
public void setAddress(String address)
|
||||
{
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the JID has relay support.
|
||||
*
|
||||
* @return <tt>true</tt> if relay is supported, <tt>false</tt> otherwise
|
||||
*/
|
||||
public boolean isRelaySupported()
|
||||
{
|
||||
return relaySupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the relay support corresponding to this JID.
|
||||
*
|
||||
* @param relaySupported relay value to set
|
||||
*/
|
||||
public void setRelay(boolean relaySupported)
|
||||
{
|
||||
this.relaySupported = relaySupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<String, String> props, String namePrefix)
|
||||
{
|
||||
if(namePrefix == null)
|
||||
namePrefix = "";
|
||||
|
||||
props.put(namePrefix + JN_ADDRESS, getJID());
|
||||
|
||||
|
||||
props.put(namePrefix + JN_IS_RELAY_SUPPORTED,
|
||||
Boolean.toString(isRelaySupported()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 JingleNodeDescriptor loadDescriptor(
|
||||
Map<String, String> props,
|
||||
String namePrefix)
|
||||
{
|
||||
if(namePrefix == null)
|
||||
namePrefix = "";
|
||||
|
||||
String relayAddress = props.get(namePrefix + JN_ADDRESS);
|
||||
|
||||
if (relayAddress == null)
|
||||
return null;
|
||||
|
||||
String relayStr = props.get(namePrefix + JN_IS_RELAY_SUPPORTED);
|
||||
|
||||
boolean relay = false;
|
||||
|
||||
try
|
||||
{
|
||||
relay = Boolean.parseBoolean(relayStr);
|
||||
}
|
||||
catch(Throwable t)
|
||||
{
|
||||
}
|
||||
|
||||
JingleNodeDescriptor relayServer =
|
||||
new JingleNodeDescriptor(relayAddress,
|
||||
relay);
|
||||
|
||||
return relayServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <tt>String</tt> representation of this descriptor
|
||||
*
|
||||
* @return a <tt>String</tt> representation of this descriptor.
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return "JingleNodesDesc: " + getJID() + " relay:"
|
||||
+ isRelaySupported();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue