Ongoing work on integrating ICE for SIP

ice4sip
Emil Ivov 12 years ago
parent fbc93ae0a4
commit bb4b2ac009

@ -65,16 +65,6 @@ public class IceUdpTransportManager
*/
protected final Agent iceAgent;
/**
* Default STUN server address.
*/
protected static final String DEFAULT_STUN_SERVER_ADDRESS = "stun.jitsi.net";
/**
* Default STUN server port.
*/
protected static final int DEFAULT_STUN_SERVER_PORT = 3478;
/**
* Creates a new instance of this transport manager, binding it to the
* specified peer.
@ -86,187 +76,85 @@ public IceUdpTransportManager(CallPeerJabberImpl callPeer)
{
super(callPeer);
iceAgent = createIceAgent();
//FIXME: initiator == controlling is only true the first time in a call
//and not for ice restarts. ICE is smart so this isn't breaking anything
//but it still sucks.
iceAgent.setControlling(!callPeer.isInitiator());
iceAgent.addStateChangeListener(this);
}
/**
* Creates the ICE agent that we would be using in this transport manager
* for all negotiation.
* Discovers and returns a list of dynamically obtained (as opposed to
* statically configured) STUN/TURN servers for use with this account. This
* specific implementation would only implement DNS-based discovery on the
* domain of the service that is currently in use.
* <p>
* It is meant to later provide additional discovery methods.
* XEP-0215 for example.
*
* @return the ICE agent to use for all the ICE negotiation that this
* transport manager would be going through
* @return
*/
protected Agent createIceAgent()
protected StunCandidateHarvester discoverStunServerForAccount()
{
long startGatheringHarvesterTime = System.currentTimeMillis();
CallPeerJabberImpl peer = getCallPeer();
ProtocolProviderServiceJabberImpl provider = peer.getProtocolProvider();
NetworkAddressManagerService namSer = getNetAddrMgr();
boolean atLeastOneStunServer = false;
Agent agent = namSer.createIceAgent();
/*
* XEP-0176: the initiator MUST include the ICE-CONTROLLING attribute,
* the responder MUST include the ICE-CONTROLLED attribute.
*/
agent.setControlling(!peer.isInitiator());
//we will now create the harvesters
JabberAccountIDImpl accID
= (JabberAccountIDImpl) provider.getAccountID();
if (accID.isStunServerDiscoveryEnabled())
//the default server is supposed to use the same user name and
//password as the account itself.
String username
= org.jivesoftware.smack.util.StringUtils.parseName(
provider.getOurJID());
String password
= JabberActivator.getProtocolProviderFactory().loadPassword(
accID);
UserCredentials credentials = provider.getUserCredentials();
if(credentials != null)
password = credentials.getPasswordAsString();
// ask for password if not saved
if (password == null)
{
//the default server is supposed to use the same user name and
//password as the account itself.
String username
= org.jivesoftware.smack.util.StringUtils.parseName(
provider.getOurJID());
String password
= JabberActivator.getProtocolProviderFactory().loadPassword(
accID);
UserCredentials credentials = provider.getUserCredentials();
if(credentials != null)
password = credentials.getPasswordAsString();
// ask for password if not saved
if (password == null)
//create a default credentials object
credentials = new UserCredentials();
credentials.setUserName(accID.getUserID());
//request a password from the user
credentials
= provider.getAuthority().obtainCredentials(
accID.getDisplayName(),
credentials,
SecurityAuthority.AUTHENTICATION_REQUIRED);
// in case user has canceled the login window
if(credentials == null)
return null;
//extract the password the user passed us.
char[] pass = credentials.getPassword();
// the user didn't provide us a password (i.e. canceled the
// operation)
if(pass == null)
return null;
password = new String(pass);
if (credentials.isPasswordPersistent())
{
//create a default credentials object
credentials = new UserCredentials();
credentials.setUserName(accID.getUserID());
//request a password from the user
credentials
= provider.getAuthority().obtainCredentials(
accID.getDisplayName(),
credentials,
SecurityAuthority.AUTHENTICATION_REQUIRED);
// in case user has canceled the login window
if(credentials == null)
return null;
//extract the password the user passed us.
char[] pass = credentials.getPassword();
// the user didn't provide us a password (i.e. canceled the
// operation)
if(pass == null)
return null;
password = new String(pass);
if (credentials.isPasswordPersistent())
{
JabberActivator.getProtocolProviderFactory()
.storePassword(accID, password);
}
}
StunCandidateHarvester autoHarvester
= namSer.discoverStunServer(
accID.getService(),
StringUtils.getUTF8Bytes(username),
StringUtils.getUTF8Bytes(password));
if (logger.isInfoEnabled())
logger.info("Auto discovered harvester is " + autoHarvester);
if (autoHarvester != null)
{
atLeastOneStunServer = true;
agent.addCandidateHarvester(autoHarvester);
JabberActivator.getProtocolProviderFactory()
.storePassword(accID, password);
}
}
//now create stun server descriptors for whatever other STUN/TURN
//servers the user may have set.
for(StunServerDescriptor desc : accID.getStunServers())
{
TransportAddress addr
= new TransportAddress(
desc.getAddress(),
desc.getPort(),
Transport.UDP);
// if we get STUN server from automatic discovery, it may just
// be server name (i.e. stun.domain.org) and it may be possible that
// it cannot be resolved
if(addr.getAddress() == null)
{
logger.info("Unresolved address for " + addr);
continue;
}
StunCandidateHarvester harvester;
if(desc.isTurnSupported())
{
//Yay! a TURN server
harvester
= new TurnCandidateHarvester(
addr,
new LongTermCredential(
desc.getUsername(),
desc.getPassword()));
}
else
{
//this is a STUN only server
harvester = new StunCandidateHarvester(addr);
}
if (logger.isInfoEnabled())
logger.info("Adding pre-configured harvester " + harvester);
atLeastOneStunServer = true;
agent.addCandidateHarvester(harvester);
}
if(!atLeastOneStunServer && accID.isUseDefaultStunServer())
{
/* we have no configured or discovered STUN server so takes the
* default provided by us if user allows it
*/
TransportAddress addr
= new TransportAddress(
DEFAULT_STUN_SERVER_ADDRESS,
DEFAULT_STUN_SERVER_PORT,
Transport.UDP);
agent.addCandidateHarvester(new StunCandidateHarvester(addr));
}
/* Jingle nodes candidate */
if(accID.isJingleNodesRelayEnabled())
{
/* this method is blocking until Jingle Nodes auto-discovery (if
* enabled) finished
*/
SmackServiceNode serviceNode = provider.getJingleNodesServiceNode();
if(serviceNode != null)
{
agent.addCandidateHarvester(
new JingleNodesHarvester(serviceNode));
}
}
if(accID.isUPNPEnabled())
agent.addCandidateHarvester(new UPNPHarvester());
long stopGatheringHarvesterTime = System.currentTimeMillis();
if (logger.isInfoEnabled())
{
long gatheringHarvesterTime
= stopGatheringHarvesterTime - startGatheringHarvesterTime;
logger.info(
"End gathering harvester within " + gatheringHarvesterTime
+ " ms");
}
return agent;
return namSer.discoverStunServer(
accID.getService(),
StringUtils.getUTF8Bytes(username),
StringUtils.getUTF8Bytes(password));
}
/**
@ -603,7 +491,6 @@ public void startCandidateHarvest(
throws OperationFailedException
{
this.cpeList = ourAnswer;
super.startCandidateHarvest(theirOffer, ourAnswer, transportInfoSender);
}
@ -769,19 +656,6 @@ public List<ContentPacketExtension> wrapupCandidateHarvest()
return cpeList;
}
/**
* Returns a reference to the {@link NetworkAddressManagerService}. The only
* reason this method exists is that {@link JabberActivator
* #getNetworkAddressManagerService()} is too long to write and makes code
* look clumsy.
*
* @return a reference to the {@link NetworkAddressManagerService}.
*/
private static NetworkAddressManagerService getNetAddrMgr()
{
return JabberActivator.getNetworkAddressManagerService();
}
/**
* Starts the connectivity establishment of the associated ICE
* <tt>Agent</tt>.

@ -157,8 +157,8 @@ private SessionDescription createFirstOffer()
mediaDescs);
//ICE HACK - please fix
//new IceTransportManagerSipImpl(getPeer()).startCandidateHarvest(
// sDes, null, false, false, false, false, false );
new IceTransportManagerSipImpl(getPeer()).startCandidateHarvest(
sDes, null, false, false, false, false, false );
this.localSess = sDes;
return localSess;

@ -84,7 +84,6 @@ public void startCandidateHarvest(SessionDescription ourOffer,
throws OperationFailedException
{
iceAgent = createIceAgent();
iceAgent.setControlling(true);
//obviously we ARE the controlling agent since we are the ones creating
//the offer.

@ -802,8 +802,7 @@ public boolean isEncryptionProtocolEnabled(String encryptionProtocolName)
* @return the list of STUN servers that this account is currently
* configured to use.
*/
public List<StunServerDescriptor> getStunServers(
BundleContext bundleContext)
public List<StunServerDescriptor> getStunServers()
{
Map<String, String> accountProperties = getAccountProperties();
List<StunServerDescriptor> stunServerList
@ -823,7 +822,6 @@ public List<StunServerDescriptor> getStunServers(
break;
String password = this.loadStunPassword(
bundleContext,
this,
ProtocolProviderFactory.STUN_PREFIX + i);
@ -839,20 +837,17 @@ public List<StunServerDescriptor> getStunServers(
/**
* Returns the password for the STUN server with the specified prefix.
*
* @param bundleContext the OSGi bundle context that we are currently
* running in.
* @param accountID account ID
* @param namePrefix name prefix
*
* @return password or null if empty
*/
protected static String loadStunPassword(BundleContext bundleContext,
AccountID accountID,
protected static String loadStunPassword(AccountID accountID,
String namePrefix)
{
ProtocolProviderFactory providerFactory
= ProtocolProviderFactory.getProtocolProviderFactory(
bundleContext,
ProtocolProviderActivator.getBundleContext(),
accountID.getSystemProtocolName());
String password = null;
@ -861,12 +856,12 @@ protected static String loadStunPassword(BundleContext bundleContext,
= className.substring(0, className.lastIndexOf('.'));
String accountPrefix = ProtocolProviderFactory.findAccountPrefix(
bundleContext,
ProtocolProviderActivator.getBundleContext(),
accountID, packageSourceName);
CredentialsStorageService credentialsService
= ServiceUtils.getService(
bundleContext,
ProtocolProviderActivator.getBundleContext(),
CredentialsStorageService.class);
try

@ -12,9 +12,14 @@
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
import org.ice4j.*;
import org.ice4j.ice.*;
import org.ice4j.ice.harvest.*;
import org.ice4j.security.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.util.*;
/**
* <tt>TransportManager</tt>s are responsible for allocating ports, gathering
@ -36,6 +41,16 @@ public abstract class TransportManager<U extends MediaAwareCallPeer<?, ?, ?>>
private static final Logger logger
= Logger.getLogger(TransportManager.class);
/**
* Default STUN server address.
*/
protected static final String DEFAULT_STUN_SERVER_ADDRESS = "stun.jitsi.net";
/**
* Default STUN server port.
*/
protected static final int DEFAULT_STUN_SERVER_PORT = 3478;
/**
* The port tracker that we should use when binding generic media streams.
* <p>
@ -783,6 +798,22 @@ public static String getICECandidateExtendedType(
return null;
}
/**
* Discovers and returns a list of dynamically obtained (as opposed to
* statically configured) STUN/TURN servers for use with this account. This
* specific implementation would only implement DNS-based discovery on the
* domain of the service that is currently in use. Protocol-specific
* implementations can provide additional discovery methods, such as
* XEP-0215 for example.
*
* @return
*/
protected StunCandidateHarvester discoverStunServerForAccount()
{
//TODO: add a default implementation here.
return null;
}
/**
* Creates the ICE agent that we would be using in this transport manager
@ -793,10 +824,98 @@ public static String getICECandidateExtendedType(
*/
protected Agent createIceAgent()
{
//work in progress
return null;
ProtocolProviderService provider = getCallPeer().getProtocolProvider();
NetworkAddressManagerService namSer = getNetAddrMgr();
boolean atLeastOneStunServer = false;
Agent agent = namSer.createIceAgent();
//we will now create the harvesters
AccountID accID = provider.getAccountID();
if (accID.isStunServerDiscoveryEnabled())
{
StunCandidateHarvester autoHarvester
= discoverStunServerForAccount();
if(autoHarvester != null)
{
if (logger.isInfoEnabled())
logger.info("Auto discovered harvester: " + autoHarvester);
if (autoHarvester != null)
{
atLeastOneStunServer = true;
agent.addCandidateHarvester(autoHarvester);
}
}
}
//now create stun server descriptors for whatever other STUN/TURN
//servers the user may have set.
for(StunServerDescriptor desc : accID.getStunServers())
{
TransportAddress addr
= new TransportAddress(
desc.getAddress(),
desc.getPort(),
Transport.UDP);
// if we get STUN server from automatic discovery, it may just
// be server name (i.e. stun.domain.org) and it may be possible that
// it cannot be resolved
if(addr.getAddress() == null)
{
logger.info("Unresolved address for " + addr);
continue;
}
StunCandidateHarvester harvester;
if(desc.isTurnSupported())
{
//Yay! a TURN server
harvester
= new TurnCandidateHarvester(
addr,
new LongTermCredential(
desc.getUsername(),
desc.getPassword()));
}
else
{
//this is a STUN only server
harvester = new StunCandidateHarvester(addr);
}
if (logger.isInfoEnabled())
logger.info("Adding pre-configured harvester " + harvester);
atLeastOneStunServer = true;
agent.addCandidateHarvester(harvester);
}
if(!atLeastOneStunServer && accID.isUseDefaultStunServer())
{
/* we have no configured or discovered STUN server so takes the
* default provided by us if user allows it
*/
TransportAddress addr
= new TransportAddress(
DEFAULT_STUN_SERVER_ADDRESS,
DEFAULT_STUN_SERVER_PORT,
Transport.UDP);
agent.addCandidateHarvester(new StunCandidateHarvester(addr));
}
if(accID.isUPNPEnabled())
agent.addCandidateHarvester(new UPNPHarvester());
return agent;
}
/**
* Creates an {@link IceMediaStream} with the specified <tt>media</tt>
* name.
@ -815,4 +934,16 @@ protected IceMediaStream createIceStream(String media, Agent agent)
{
return null;
}
/**
* Returns a reference to the {@link NetworkAddressManagerService}. This is
* only a convenience method.
*
* @return a reference to the {@link NetworkAddressManagerService}
* currently in use in our environment.
*/
public static NetworkAddressManagerService getNetAddrMgr()
{
return ProtocolMediaActivator.getNetworkAddressManagerService();
}
}

Loading…
Cancel
Save