Avoid unnecessary DNS lookups for SIP

cusax-fix
Ingo Bauersachs 15 years ago
parent 3b7274d9bb
commit aaa147c435

@ -28,7 +28,8 @@ org.osgi.framework.system.packages.extra= \
sun.net.util; \
sun.net.dns; \
sun.security.action; \
sun.security.pkcs11;
sun.security.pkcs11; \
sun.reflect;
#
@ -41,7 +42,10 @@ org.osgi.framework.system.packages.extra= \
#
felix.auto.start.10= \
file:lib/bundle/junit.jar
reference:file:lib/bundle/junit.jar \
reference:file:lib/installer-exclude/easymock-3.1.jar \
reference:file:lib/installer-exclude/objenesis-1.2.jar \
reference:file:lib/installer-exclude/cglib-nodep.osgi-2.1_3.jar
# file:lib/bundle/shell.jar \
# file:lib/bundle/bundlerepository.jar \
# file:lib/bundle/servicebinder.jar \

@ -9,6 +9,7 @@
import gov.nist.javax.sip.address.*;
import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.message.*;
import net.java.sip.communicator.impl.protocol.sip.net.*;
import net.java.sip.communicator.impl.protocol.sip.security.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
@ -155,31 +156,9 @@ public class ProtocolProviderServiceSipImpl
private SipSecurityManager sipSecurityManager = null;
/**
* The address and port of an outbound proxy if we have one (remains null
* if we are not using a proxy).
* Address resolver for the outbound proxy connection.
*/
private InetSocketAddress outboundProxySocketAddress = null;
/**
* The transport used by our outbound proxy (remains null
* if we are not using a proxy).
*/
private String outboundProxyTransport = null;
/**
* Array of ordered addresses to try when connecting.
*/
private InetSocketAddress[] connectionAddresses = null;
/**
* Array of ordered addresses transports to try when connecting.
*/
private String[] connectionTransports = null;
/**
* The InetAddress we are connecting to, outbound proxy.
*/
private InetSocketAddress currentConnectionAddress = null;
private ProxyConnection connection;
/**
* The logo corresponding to the jabber protocol.
@ -320,11 +299,17 @@ public void register(SecurityAuthority authority)
sipSecurityManager.setSecurityAuthority(authority);
initRegistrarConnection();
initOutboundProxy(0);
//connect to the Registrar.
if (sipRegistrarConnection != null)
sipRegistrarConnection.register();
connection = ProxyConnection.create(this);
if(!registerUsingNextAddress())
{
logger.error("No address found for " + this);
fireRegistrationStateChanged(
RegistrationState.UNREGISTERED,
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND,
"Invalid or inaccessible server address.");
}
}
/**
@ -340,7 +325,7 @@ public void unregister()
{
if(getRegistrationState().equals(RegistrationState.UNREGISTERED)
|| getRegistrationState().equals(RegistrationState.UNREGISTERING)
|| getRegistrationState().equals(RegistrationState.CONNECTION_FAILED))
|| getRegistrationState().equals(RegistrationState.CONNECTION_FAILED))
{
return;
}
@ -1013,9 +998,7 @@ public void run()
addressFactory = null;
sipSecurityManager = null;
connectionAddresses = null;
connectionTransports = null;
currentConnectionAddress = null;
connection = null;
methodProcessors.clear();
@ -1386,18 +1369,14 @@ public ListeningPoint getListeningPoint(String transport)
logger.trace("Query for a " + transport + " listening point");
//override the transport in case we have an outbound proxy.
if(outboundProxySocketAddress != null)
if(connection.getAddress() != null)
{
if (logger.isTraceEnabled())
logger.trace("Will use proxy address");
transport = outboundProxyTransport;
transport = connection.getTransport();
}
if( transport == null
|| transport.trim().length() == 0
|| ( ! transport.trim().equalsIgnoreCase(ListeningPoint.TCP)
&& ! transport.trim().equalsIgnoreCase(ListeningPoint.UDP)
&& ! transport.trim().equalsIgnoreCase(ListeningPoint.TLS)))
if(!isValidTransport(transport))
{
transport = getDefaultTransport();
}
@ -1425,21 +1404,6 @@ else if(transport.equalsIgnoreCase(ListeningPoint.TLS))
return lp;
}
/**
* Returns the default listening point that we should use to contact the
* intended destination.
*
* @param intendedDestination the address that we will be trying to contact
* through the listening point we are trying to obtain.
*
* @return the listening point that we should use to contact the
* intended destination.
*/
public ListeningPoint getListeningPoint(Address intendedDestination)
{
return getListeningPoint((SipURI)intendedDestination.getURI());
}
/**
* Returns the default listening point that we should use to contact the
* intended destination.
@ -1452,9 +1416,7 @@ public ListeningPoint getListeningPoint(Address intendedDestination)
*/
public ListeningPoint getListeningPoint(SipURI intendedDestination)
{
String transport = intendedDestination.getTransportParam();
return getListeningPoint(transport);
return getListeningPoint(intendedDestination.getTransportParam());
}
/**
@ -1652,48 +1614,9 @@ public Address getOurSipAddress(SipURI intendedDestination)
}
}
/**
* In case we are using an outbound proxy this method returns
* a suitable string for use with Router.
* The method returns <tt>null</tt> otherwise.
*
* @return the string of our outbound proxy if we are using one and
* <tt>null</tt> otherwise.
*/
public String getOutboundProxyString()
public ProxyConnection getConnection()
{
InetAddress proxyAddress = outboundProxySocketAddress.getAddress();
StringBuilder proxyStringBuffer
= new StringBuilder(proxyAddress.getHostAddress());
if(proxyAddress instanceof Inet6Address)
{
proxyStringBuffer.insert(0, '[');
proxyStringBuffer.append(']');
}
proxyStringBuffer.append(':');
proxyStringBuffer.append(outboundProxySocketAddress.getPort());
proxyStringBuffer.append('/');
proxyStringBuffer.append(outboundProxyTransport);
return proxyStringBuffer.toString();
}
/**
* Compares an InetAddress against the active outbound proxy. The comparison
* is by reference, not equals.
*
* @param addressToTest The addres to test.
* @return True when the InetAddress is the same as the outbound proxy.
*/
public boolean matchesInetAddress(InetAddress addressToTest)
{
// if the proxy is not yet initialized then this is not the provider that
// caused this comparison
if(outboundProxySocketAddress == null)
return false;
return addressToTest == outboundProxySocketAddress.getAddress();
return connection;
}
/**
@ -1704,259 +1627,7 @@ public boolean matchesInetAddress(InetAddress addressToTest)
*/
public boolean isSignalingTransportSecure()
{
return ListeningPoint.TLS.equalsIgnoreCase(outboundProxyTransport);
}
/**
* Extracts all properties concerning the usage of an outbound proxy for
* this account.
* @param ix index of the address to use.
*/
private void initOutboundProxy(int ix)
{
//First init the proxy address
String proxyAddressStr =
accountID
.getAccountPropertyString(ProtocolProviderFactory.
PROXY_ADDRESS);
boolean proxyAddressAndPortEntered = false;
if(proxyAddressStr == null || proxyAddressStr.trim().length() == 0
|| accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_AUTO_CONFIG, false))
{
String userID = accountID.getAccountPropertyString(
ProtocolProviderFactory.USER_ID);
int domainIx = userID.indexOf("@");
if(domainIx > 0)
{
proxyAddressStr = userID.substring(domainIx + 1);
}
else
{
proxyAddressStr = accountID
.getAccountPropertyString(ProtocolProviderFactory.
SERVER_ADDRESS);
if(proxyAddressStr == null || proxyAddressStr.trim().length() == 0)
{
/* registrarless account */
return;
}
}
}
else
{
if(accountID.getAccountProperty(ProtocolProviderFactory.PROXY_PORT)
!= null)
{
proxyAddressAndPortEntered = true;
}
}
//init proxy port
int proxyPort = ListeningPoint.PORT_5060;
//proxy transport
String proxyTransport = accountID.getAccountPropertyString(
ProtocolProviderFactory.PREFERRED_TRANSPORT);
if (proxyTransport != null && proxyTransport.length() > 0)
{
if (!proxyTransport.equals(ListeningPoint.UDP)
&& !proxyTransport.equals(ListeningPoint.TCP)
&& !proxyTransport.equals(ListeningPoint.TLS))
{
throw new IllegalArgumentException(proxyTransport
+ " is not a valid transport protocol. Transport must be "
+ "left blank or set to TCP, UDP or TLS.");
}
}
else
{
proxyTransport = getDefaultTransport();
}
InetSocketAddress proxySocketAddress = null;
try
{
//check if user has overridden proxy port.
proxyPort = accountID.getAccountPropertyInt(
ProtocolProviderFactory.PROXY_PORT,
proxyPort);
if (proxyPort > NetworkUtils.MAX_PORT_NUMBER)
{
throw new IllegalArgumentException(proxyPort + " is larger than "
+ NetworkUtils.MAX_PORT_NUMBER
+ " and does not therefore represent a valid port number.");
}
if(accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_AUTO_CONFIG, false))
{
if(connectionAddresses == null)
{
ArrayList<InetSocketAddress> proxySocketAddressesList
= new ArrayList<InetSocketAddress>();
ArrayList<String> proxyTransportsList
= new ArrayList<String>();
resolveSipAddress(
proxyAddressStr,
proxyTransport,
proxySocketAddressesList,
proxyTransportsList,
true);
connectionTransports = proxyTransportsList.toArray(
new String[proxyTransportsList.size()]);
connectionAddresses = proxySocketAddressesList.toArray(
new InetSocketAddress[proxySocketAddressesList.size()]);
}
proxyTransport = connectionTransports[ix];
proxySocketAddress = connectionAddresses[ix];
}
else
{
// according rfc3263 if proxy address and port are
// explicitly entered don't make SRV queries
if(proxyAddressAndPortEntered)
{
if(connectionAddresses == null)
{
ArrayList<InetSocketAddress> addresses
= new ArrayList<InetSocketAddress>();
resolveAddresses(
proxyAddressStr,
addresses,
proxyPort);
connectionAddresses = addresses.toArray(
new InetSocketAddress[addresses.size()]);
// we have transport, use it for all addresses
connectionTransports = new String[addresses.size()];
Arrays.fill(connectionTransports, proxyTransport);
}
// only set if enough results found
if(connectionAddresses.length > ix)
proxySocketAddress = connectionAddresses[ix];
}
else
{
if(connectionAddresses == null)
{
ArrayList<InetSocketAddress> proxySocketAddressesList
= new ArrayList<InetSocketAddress>();
ArrayList<String> proxyTransportsList
= new ArrayList<String>();
resolveSipAddress(
proxyAddressStr,
proxyTransport,
proxySocketAddressesList,
proxyTransportsList,
false);
connectionTransports = proxyTransportsList.toArray(
new String[proxyTransportsList.size()]);
connectionAddresses =
proxySocketAddressesList.toArray(
new InetSocketAddress[
proxySocketAddressesList.size()]);
}
proxyTransport = connectionTransports[ix];
proxySocketAddress = connectionAddresses[ix];
}
}
if(proxySocketAddress == null)
throw new UnknownHostException();
if(this.currentConnectionAddress == null)
this.currentConnectionAddress = proxySocketAddress;
proxyPort = proxySocketAddress.getPort();
if (logger.isTraceEnabled())
logger.trace("Setting proxy address = " + proxyAddressStr);
// We should set here the property to indicate that the proxy
// address is validated. When we load stored accounts we check
// this property in order to prevent checking again the proxy
// address. this is needed because in the case we don't have
// network while loading the application we still want to have
// our accounts loaded.
accountID.putAccountProperty(
ProtocolProviderFactory.PROXY_ADDRESS_VALIDATED,
Boolean.toString(true));
}
catch (UnknownHostException ex)
{
logger.error(proxyAddressStr
+ " appears to be an either invalid"
+ " or inaccessible address.",
ex);
boolean isProxyValidated =
accountID.getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_ADDRESS_VALIDATED, false);
// We should check here if the proxy address was already validated.
// When we load stored accounts we want to prevent checking again the
// proxy address. This is needed because in the case we don't have
// network while loading the application we still want to have our
// accounts loaded.
if (!isProxyValidated)
{
throw new IllegalArgumentException(
proxyAddressStr
+ " appears to be an either invalid or"
+ " inaccessible address.",
ex);
}
}
if(connectionAddresses == null
|| connectionAddresses.length == 0)
{
sipRegistrarConnection = null;
// no addresses, maybe network down, lets try
// resolving them later
connectionAddresses = null;
connectionTransports = null;
fireRegistrationStateChanged(
RegistrationState.UNREGISTERED,
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_SERVER_NOT_FOUND,
"Invalid or inaccessible server address.");
return;
}
// Return if no proxy is specified or if the proxyAddress is null.
if(proxySocketAddress == null)
{
return;
}
// lets change registrar connections transport
// make sure it reflects the transport we choose from DNS records
// registrar connection can be null while creating accounts
if(sipRegistrarConnection != null)
sipRegistrarConnection.setTransport(proxyTransport);
//store a reference to our sip proxy so that we can use it when
//constructing via and contact headers.
this.outboundProxySocketAddress
= new InetSocketAddress(proxySocketAddress.getAddress(), proxyPort);
this.outboundProxyTransport = proxyTransport;
return ListeningPoint.TLS.equalsIgnoreCase(connection.getTransport());
}
/**
@ -2057,20 +1728,13 @@ public void unregisterMethodProcessor(String method,
*/
public String getDefaultTransport()
{
if( sipRegistrarConnection != null)
{
String registrarTransport = sipRegistrarConnection.getTransport();
if( registrarTransport != null
&& registrarTransport.length() > 0)
{
return registrarTransport;
}
}
if(outboundProxySocketAddress != null
&& outboundProxyTransport != null)
if(sipRegistrarConnection != null
&& !sipRegistrarConnection.isRegistrarless()
&& connection != null
&& connection.getAddress() != null
&& connection.getTransport() != null)
{
return outboundProxyTransport;
return connection.getTransport();
}
else
{
@ -2108,19 +1772,6 @@ public SipProvider getDefaultJainSipProvider()
return getJainSipProvider(getDefaultTransport());
}
/**
* Returns the listening point that corresponds to the transport returned by
* getDefaultTransport(). Equivalent to calling
* getListeningPoint(getDefaultTransport())
*
* @return the Jain SipProvider that corresponds to the transport returned
* by getDefaultTransport().
*/
public ListeningPoint getDefaultListeningPoint()
{
return getListeningPoint(getDefaultTransport());
}
/**
* Returns the display name string that the user has set as a display name
* for this account.
@ -2517,320 +2168,6 @@ public Address parseAddressString(String uriStr)
return toAddress;
}
/**
* Tries to resolve <tt>address</tt> into a valid InetSocketAddress using
* an <tt>SRV</tt> query where it exists and A/AAAA where it doesn't.
* If there is no SRV,A or AAAA records return the socket address created
* with the supplied <tt>address</tt>, so we can keep old behaviour.
* When letting underling libs and java to resolve the address.
*
* @param address the address we'd like to resolve.
* @param transport the protocol that we'd like to use when accessing
* address.
* @param resultAddresses the list that will be filled with the result
* addresses. An <tt>InetSocketAddress</tt> instances containing the
* <tt>SRV</tt> record for <tt>address</tt> if one has been defined and the
* A/AAAA record where it hasn't.
* @param resultTransports the transports for the <tt>resultAddresses</tt>.
* @param resolveProtocol if the protocol should be resolved
* @return the transports that is used, when the <tt>transport</tt> is with
* value Auto we resolve the address with NAPTR query, if no NAPTR record
* we will use the default one.
*
* @throws UnknownHostException if <tt>address</tt> is not a valid host
* address.
*/
public void resolveSipAddress(
String address, String transport,
List<InetSocketAddress> resultAddresses,
List<String> resultTransports,
boolean resolveProtocol)
throws UnknownHostException
{
//we need to resolve the address only if its a hostname.
if(NetworkUtils.isValidIPAddress(address))
{
InetAddress addressObj = NetworkUtils.getInetAddress(address);
//this is an ip address so we need to return default ports since
//we can't get them from a DNS.
int port = ListeningPoint.PORT_5060;
if(transport.equalsIgnoreCase(ListeningPoint.TLS))
port = ListeningPoint.PORT_5061;
resultTransports.add(transport);
resultAddresses.add(new InetSocketAddress(addressObj, port));
// as its ip address return, no dns is needed.
return;
}
// first make NAPTR resolve to get protocol, if needed
if(resolveProtocol)
{
try
{
String[][] naptrRecords = NetworkUtils.getNAPTRRecords(address);
if(naptrRecords != null && naptrRecords.length > 0)
{
for(String[] rec : naptrRecords)
{
resolveSRV(
rec[2],
rec[1],
resultAddresses,
resultTransports,
true);
}
// NAPTR found use only it
if(logger.isInfoEnabled())
logger.info("Found NAPTR record and using it:"
+ resultAddresses);
// return only if found something
if(resultAddresses.size() > 0
&& resultTransports.size() > 0)
return;
}
}
catch (ParseException e)
{
logger.error("Error parsing dns record.", e);
}
}
//try to obtain SRV mappings from the DNS
try
{
if(resolveProtocol)
{
String[] transports = new String[]{
ListeningPoint.TLS,
ListeningPoint.TCP,
ListeningPoint.UDP
};
for(String tp : transports)
{
resolveSRV(
address,
tp,
resultAddresses,
resultTransports,
false);
if(!resultAddresses.isEmpty())
{
transport = tp;
break;
}
}
}
else
{
resolveSRV(
address,
transport,
resultAddresses,
resultTransports,
false);
}
}
catch (ParseException e)
{
logger.error("Error parsing dns record.", e);
}
//no SRV means default ports
int defaultPort = ListeningPoint.PORT_5060;
if(transport.equalsIgnoreCase(ListeningPoint.TLS))
defaultPort = ListeningPoint.PORT_5061;
ArrayList<InetSocketAddress> tempResultAddresses
= new ArrayList<InetSocketAddress>();
// after checking SRVs, lets add and AAAA and A records
resolveAddresses(
address,
tempResultAddresses,
defaultPort);
for(InetSocketAddress a : tempResultAddresses)
{
if(!resultAddresses.contains(a))
{
resultAddresses.add(a);
resultTransports.add(transport);
}
}
// make sure we don't return empty array
if(resultAddresses.size() == 0)
{
resultAddresses.add(new InetSocketAddress(address, defaultPort));
resultTransports.add(transport);
// there were no SRV mappings so we only need to A/AAAA resolve the
// address. Do this before we instantiate the
// resulting InetSocketAddress because its constructor
// suppresses UnknownHostException-s and we want to know if
// something goes wrong.
@SuppressWarnings("unused")
InetAddress addressObj = InetAddress.getByName(address);
}
}
/**
* Resolves the given address. Resolves A and AAAA records and returns
* them in <tt>resultAddresses</tt> ordered according
* <tt>preferIPv6Addresses</tt> option.
* @param address the address to resolve.
* @param resultAddresses the List in which we provide the result.
* @param defaultPort the port to use for the result address.
* @throws UnknownHostException its not supposed to be thrown, cause
* the address we use is an ip address.
*/
private void resolveAddresses(
String address, List<InetSocketAddress> resultAddresses,
int defaultPort)
throws UnknownHostException
{
//we need to resolve the address only if its a hostname.
if(NetworkUtils.isValidIPAddress(address))
{
InetAddress addressObj = NetworkUtils.getInetAddress(address);
resultAddresses.add(new InetSocketAddress(addressObj, defaultPort));
// as its ip address return, no dns is needed.
return;
}
try
{
for(InetSocketAddress a :
NetworkUtils.getAandAAAARecords(address, defaultPort))
{
resultAddresses.add(a);
}
}
catch (ParseException ex)
{
logger.error("Error parsing dns record.", ex);
}
if(resultAddresses.size() == 0)
logger.warn("No AAAA and A record found for " + address);
}
/**
* Tries to resolve <tt>address</tt> into a valid InetSocketAddress using
* an <tt>SRV</tt> query where it exists and A/AAAA where it doesn't. The
* method assumes that the transport that we'll be using when connecting to
* address is the one that has been defined as default for this provider.
*
* @param address the address we'd like to resolve.
*
* @return an <tt>InetSocketAddress</tt> instance containing the
* <tt>SRV</tt> record for <tt>address</tt> if one has been defined and the
* A/AAAA record where it hasn't.
*
* @throws UnknownHostException if <tt>address</tt> is not a valid host
* address.
*/
public InetSocketAddress resolveSipAddress(String address)
throws UnknownHostException
{
ArrayList<InetSocketAddress> socketAddressesList =
new ArrayList<InetSocketAddress>();
resolveSipAddress(address, getDefaultTransport(), socketAddressesList,
new ArrayList<String>(),
getAccountID().getAccountPropertyBoolean(
ProtocolProviderFactory.PROXY_AUTO_CONFIG, false));
return socketAddressesList.get(0);
}
/**
* Resolves the SRV records add their corresponding AAAA and A records
* in the <tt>resultAddresses</tt> ordered by the preference
* <tt>preferIPv6Addresses</tt> and their corresponding <tt>transport</tt>
* in the <tt>resultTransports</tt>.
* @param address the address to resolve.
* @param transport the transport to use
* @param resultAddresses the result address after resolve.
* @param resultTransports and the addresses transports.
* @param srvQueryString is the supplied address is of type
* _sip(s)._protocol.address, a string ready for srv queries, used
* when we have a NAPTR returned records with value <tt>true</tt>.
* @throws ParseException exception when parsing dns address
*/
private void resolveSRV(String address,
String transport,
List<InetSocketAddress> resultAddresses,
List<String> resultTransports,
boolean srvQueryString)
throws ParseException
{
SRVRecord srvRecords[] = null;
if(srvQueryString)
{
srvRecords = NetworkUtils.getSRVRecords(address);
}
else
{
srvRecords = NetworkUtils.getSRVRecords(
transport.equalsIgnoreCase(ListeningPoint.TLS)
? "sips" : "sip",
transport.equalsIgnoreCase(ListeningPoint.UDP)
? ListeningPoint.UDP : ListeningPoint.TCP,
address);
}
if(srvRecords != null)
{
ArrayList<InetSocketAddress> tempResultAddresses
= new ArrayList<InetSocketAddress>();
for(SRVRecord s : srvRecords)
{
// add corresponding A and AAAA records
// to the host address from SRV records
try
{
// as these are already resolved addresses (the SRV res.)
// lets get it without triggering a PTR
resolveAddresses(
s.getTarget(),
tempResultAddresses,
s.getPort());
}
catch(UnknownHostException e)
{
logger.warn("Address unknown:" + s.getTarget(), e);
}
/* add and every SRV address itself if not already there
if(!tempResultAddresses.contains(s))
tempResultAddresses.add(s);
*/
if (logger.isTraceEnabled())
logger.trace("Returned SRV " + s);
}
for(InetSocketAddress a : tempResultAddresses)
{
if(!resultAddresses.contains(a))
{
resultAddresses.add(a);
resultTransports.add(transport);
}
}
}
}
/**
* Returns the <tt>InetAddress</tt> that is most likely to be to be used
* as a next hop when contacting the specified <tt>destination</tt>. This is
@ -2854,7 +2191,6 @@ public InetSocketAddress getIntendedDestination(Address destination)
return getIntendedDestination((SipURI)destination.getURI());
}
/**
* Returns the <tt>InetAddress</tt> that is most likely to be to be used
* as a next hop when contacting the specified <tt>destination</tt>. This is
@ -2905,7 +2241,7 @@ public InetSocketAddress getIntendedDestination(String host)
//but the destination could only be known to our outbound proxy
//if we have one. If this is the case replace the destination
//address with that of the proxy.(report by Dan Bogos)
InetSocketAddress outboundProxy = outboundProxySocketAddress;
InetSocketAddress outboundProxy = connection.getAddress();
if(outboundProxy != null)
{
@ -2915,16 +2251,11 @@ public InetSocketAddress getIntendedDestination(String host)
}
else
{
try
{
destinationInetAddress = resolveSipAddress(host);
}
catch (UnknownHostException ex)
{
throw new IllegalArgumentException(
host + " is not a valid internet address.",
ex);
}
ProxyConnection tempConn = new AutoProxyConnection(
(SipAccountID)getAccountID(),
host,
getDefaultTransport());
destinationInetAddress = tempConn.getAddress();
}
if(logger.isDebugEnabled())
@ -3046,65 +2377,41 @@ else if(message instanceof TimeoutEvent)
*/
boolean registerUsingNextAddress()
{
// means no connection
if(connectionAddresses == null)
if(connection == null)
return false;
int i = 0;
for (; i < connectionAddresses.length; i++)
{
if(connectionAddresses[i].equals(currentConnectionAddress))
break;
}
if(i + 1 < connectionAddresses.length)
try
{
changeAddress(i + 1);
try
if(sipRegistrarConnection.isRegistrarless())
{
sipRegistrarConnection.setTransport(getDefaultTransport());
sipRegistrarConnection.register();
return true;
}
catch (Throwable e)
else if(connection.getNextAddress())
{
logger.error("Cannot send register!", e);
sipRegistrarConnection.setRegistrationState(
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
"A timeout occurred while trying to connect to the server.");
sipRegistrarConnection.setTransport(connection.getTransport());
sipRegistrarConnection.register();
return true;
}
return true;
}
catch (Throwable e)
{
logger.error("Cannot send register!", e);
sipRegistrarConnection.setRegistrationState(
RegistrationState.CONNECTION_FAILED,
RegistrationStateChangeEvent.REASON_NOT_SPECIFIED,
"A timeout occurred while trying to connect to the server.");
}
// as we reached the last address lets change it to the first one
// so we don't get stuck to the last one forever, and the next time
// use again the first one
changeAddress(0);
connection.reset();
return false;
}
/**
* Change the current address used to register to ix one.
* @param ix the index of the new address to assign.
*/
private void changeAddress(int ix)
{
if(ix >= connectionAddresses.length)
return;
this.currentConnectionAddress = connectionAddresses[ix];
sipRegistrarConnection.setTransport(connectionTransports[ix]);
initOutboundProxy(ix);
}
protected InetSocketAddress getCurrentConnectionAddress()
{
return currentConnectionAddress;
}
/**
* If somewhere we got for example timeout of receiving answer to our
* requests we consider problem with network and notify the provider.
@ -3130,4 +2437,17 @@ protected void notifyConnectionFailed()
"A timeout occurred while trying to connect to the server.");
}
}
/**
* Determines whether the supplied transport is a known SIP transport method
*
* @param transport the SIP transport to check
* @return True when transport is one of UDP, TCP or TLS.
*/
public static boolean isValidTransport(String transport)
{
return ListeningPoint.UDP.equalsIgnoreCase(transport)
|| ListeningPoint.TLS.equalsIgnoreCase(transport)
|| ListeningPoint.TCP.equalsIgnoreCase(transport);
}
}

@ -126,7 +126,7 @@ private Router getRouterFor(Request request)
ProtocolProviderServiceSipImpl sipProvider
= ((ProtocolProviderServiceSipImpl) service);
String proxy = sipProvider.getOutboundProxyString();
String proxy = sipProvider.getConnection().getOutboundProxyString();
boolean forceLooseRouting = Boolean.valueOf((String)
sipProvider.getAccountID().getAccountProperty(

@ -173,7 +173,7 @@ private void connect(String serverAddress)
connection = new Socket(serverAddress, 5003);
else // lets try using our sip connected address
connection = new Socket(
sipProvider.getCurrentConnectionAddress().getAddress(), 5003);
sipProvider.getConnection().getAddress().getAddress(), 5003);
connectionWriter = new PrintStream(connection.getOutputStream());
}

@ -0,0 +1,384 @@
/*
* 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.impl.protocol.sip.net;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.*;
import java.net.*;
import java.text.*;
import javax.sip.*;
import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.util.*;
import static javax.sip.ListeningPoint.*;
/**
* Implementation of the autodetect proxy connection. Tries to resolve a SIP-
* server by querying DNS in this order: NAPTR-SRV-A; SRV-A; A.
*
* @author Ingo Bauersachs
*/
public class AutoProxyConnection
extends ProxyConnection
{
private enum State
{
New,
Naptr,
NaptrSrv,
NaptrSrvHosts,
NaptrSrvHostIPs,
Srv,
SrvHosts,
SrvHostIPs,
Hosts,
IP
}
/**
* Wrapper around {@link NetworkUtils} to support Unit Tests.
*/
protected static class LocalNetworkUtils
{
public InetAddress getInetAddress(String address)
throws UnknownHostException
{
return NetworkUtils.getInetAddress(address);
}
public String[][] getNAPTRRecords(String address)
throws ParseException
{
return NetworkUtils.getNAPTRRecords(address);
}
public SRVRecord[] getSRVRecords(String service, String proto,
String address) throws ParseException
{
return NetworkUtils.getSRVRecords(service, proto, address);
}
public InetSocketAddress[] getAandAAAARecords(String target, int port)
throws ParseException
{
return NetworkUtils.getAandAAAARecords(target, port);
}
public boolean isValidIPAddress(String address)
{
return NetworkUtils.isValidIPAddress(address);
}
public SRVRecord[] getSRVRecords(String domain)
throws ParseException
{
return NetworkUtils.getSRVRecords(domain);
}
}
private final static Logger logger
= Logger.getLogger(AutoProxyConnection.class);
private State state;
private String address;
private final String defaultTransport;
private LocalNetworkUtils nu = new LocalNetworkUtils();
private final static String[] transports = new String[]
{
ListeningPoint.TLS,
ListeningPoint.TCP,
ListeningPoint.UDP
};
private boolean hadSrvResults;
private String[][] naptrRecords;
private int naptrIndex;
private SRVRecord[] srvRecords;
private int srvRecordsIndex;
private int srvTransportIndex;
private InetSocketAddress socketAddresses[];
private int socketAddressIndex;
/**
* Creates a new instance of this class. Uses the server from the account.
*
* @param account the account of this SIP protocol instance
* @param defaultTransport the default transport to use when DNS does not
* provide a protocol through NAPTR or SRV
*/
public AutoProxyConnection(SipAccountID account, String defaultTransport)
{
super(account);
this.defaultTransport = defaultTransport;
reset();
}
/**
* Creates a new instance of this class. Uses the supplied address instead
* of the server address from the account.
*
* @param account the account of this SIP protocol instance
* @param address the domain on which to perform autodetection
* @param defaultTransport the default transport to use when DNS does not
* provide a protocol through NAPTR or SRV
*/
public AutoProxyConnection(SipAccountID account, String address,
String defaultTransport)
{
super(account);
this.defaultTransport = defaultTransport;
reset();
this.address = address;
}
/**
* Sets the NetworkUtils wrapper. Used for Unit-Testing.
* @param nu the the NetworkUtils wrapper.
*/
protected void setNetworkUtils(LocalNetworkUtils nu)
{
this.nu = nu;
}
/*
* (non-Javadoc)
*
* @see net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#
* getNextAddressFromDns()
*/
protected boolean getNextAddressFromDns()
{
try
{
return getNextAddressInternal();
}
catch(ParseException ex)
{
logger.error("Unable to get DNS data for <" + address
+ "> in state" + state, ex);
}
return false;
}
/**
* Gets the next address from DNS.
*/
private boolean getNextAddressInternal()
throws ParseException
{
switch(state)
{
case New:
state = State.Naptr;
return getNextAddressFromDns();
case IP:
if(socketAddressIndex == 0)
{
socketAddressIndex++;
try
{
socketAddress = new InetSocketAddress(
nu.getInetAddress(address),
ListeningPoint.TLS.equalsIgnoreCase(transport)
? ListeningPoint.PORT_5061
: ListeningPoint.PORT_5060
);
}
catch (UnknownHostException e)
{
//this is not supposed to happen
logger.error("invalid IP address: " + address, e);
return false;
}
transport = defaultTransport;
return true;
}
return false;
case Naptr:
naptrRecords = nu.getNAPTRRecords(address);
if(naptrRecords != null && naptrRecords.length > 0)
{
state = State.NaptrSrv;
naptrIndex = 0;
}
else
{
hadSrvResults = false;
state = State.Srv;
srvTransportIndex = 0;
}
return getNextAddressFromDns();
case NaptrSrv:
for(; naptrIndex < naptrRecords.length; naptrIndex++)
{
srvRecords = nu.getSRVRecords(
naptrRecords[naptrIndex][2]);
if(srvRecords != null && srvRecords.length > 0)
{
state = State.NaptrSrvHosts;
if(TLS.equalsIgnoreCase(naptrRecords[naptrIndex][1]))
transport = TLS;
else if(TCP.equalsIgnoreCase(naptrRecords[naptrIndex][1]))
transport = TCP;
else
transport = UDP;
srvRecordsIndex = 0;
if(getNextAddressFromDns())
{
naptrIndex++;
return true;
}
}
}
return false; //no more naptr's
case NaptrSrvHosts:
for(; srvRecordsIndex < srvRecords.length; srvRecordsIndex++)
{
socketAddresses = nu.getAandAAAARecords(
srvRecords[srvRecordsIndex].getTarget(),
srvRecords[srvRecordsIndex].getPort());
if(socketAddresses != null && socketAddresses.length > 0)
{
state = State.NaptrSrvHostIPs;
socketAddressIndex = 0;
if(getNextAddressFromDns())
{
srvRecordsIndex++;
return true;
}
}
}
state = State.NaptrSrv;
return getNextAddressFromDns(); //backtrack to next naptr
case NaptrSrvHostIPs:
if(socketAddressIndex >= socketAddresses.length)
{
state = State.NaptrSrvHosts;
return getNextAddressFromDns(); //backtrack to next srv
}
socketAddress = socketAddresses[socketAddressIndex];
socketAddressIndex++;
return true;
case Srv:
for(;srvTransportIndex < transports.length; srvTransportIndex++)
{
srvRecords = nu.getSRVRecords(
(TLS.equals(transports[srvTransportIndex])
? "sips"
: "sip"),
(UDP.equalsIgnoreCase(transports[srvTransportIndex])
? UDP
: TCP),
address);
if(srvRecords != null && srvRecords.length > 0)
{
hadSrvResults = true;
state = State.SrvHosts;
srvRecordsIndex = 0;
transport = transports[srvTransportIndex];
if(getNextAddressFromDns())
{
srvTransportIndex++;
return true;
}
}
}
if(!hadSrvResults)
{
state = State.Hosts;
socketAddressIndex = 0;
return getNextAddressFromDns();
}
return false;
case SrvHosts:
for(; srvRecordsIndex < srvRecords.length; srvRecordsIndex++)
{
socketAddresses = nu.getAandAAAARecords(
srvRecords[srvRecordsIndex].getTarget(),
srvRecords[srvRecordsIndex].getPort());
if(socketAddresses != null && socketAddresses.length > 0)
{
state = State.SrvHostIPs;
socketAddressIndex = 0;
if(getNextAddressFromDns())
{
srvRecordsIndex++;
return true;
}
}
}
state = State.Srv;
return getNextAddressFromDns(); //backtrack to next srv record
case SrvHostIPs:
if(socketAddressIndex >= socketAddresses.length)
{
state = State.SrvHosts;
return getNextAddressFromDns();
}
socketAddress = socketAddresses[socketAddressIndex];
socketAddressIndex++;
return true;
case Hosts:
transport = defaultTransport;
if(socketAddresses == null)
{
socketAddresses = nu.getAandAAAARecords(
address,
ListeningPoint.PORT_5060);
}
if(socketAddresses != null && socketAddresses.length > 0
&& socketAddressIndex < socketAddresses.length)
{
socketAddress = socketAddresses[socketAddressIndex++];
return true;
}
return false;
}
return false;
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#reset()
*/
@Override
public void reset()
{
super.reset();
state = State.New;
//determine the hostname of the proxy for autodetection:
//1) server part of the user ID
//2) name of the registrar when the user ID contains no domain
String userID = account.getAccountPropertyString(USER_ID);
int domainIx = userID.indexOf("@");
if(domainIx > 0)
{
address = userID.substring(domainIx + 1);
}
else
{
address = account.getAccountPropertyString(SERVER_ADDRESS);
if(address == null || address.trim().length() == 0)
{
//registrarless account
return;
}
}
if(nu.isValidIPAddress(address))
{
state = State.IP;
socketAddressIndex = 0;
}
}
}

@ -0,0 +1,114 @@
/*
* 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.impl.protocol.sip.net;
import static javax.sip.ListeningPoint.*;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.*;
import java.net.*;
import java.text.*;
import net.java.sip.communicator.impl.protocol.sip.*;
import net.java.sip.communicator.util.*;
/**
* Implementation of the manually configured SIP proxy connection. IP Address
* lookups are performed using the account's proxy address.
*
* @author Ingo Bauersachs
*/
public class ManualProxyConnection
extends ProxyConnection
{
private final static Logger logger
= Logger.getLogger(ManualProxyConnection.class);
private String address;
private int port;
private InetSocketAddress[] lookups;
private int lookupIndex;
/**
* Creates a new instance of this class. Uses the server from the account.
*
* @param account the account of this SIP protocol instance
*/
public ManualProxyConnection(SipAccountID account)
{
super(account);
reset();
}
/*
* (non-Javadoc)
*
* @see net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#
* getNextAddress()
*/
@Override
public boolean getNextAddressFromDns()
{
if(lookups == null)
{
try
{
lookupIndex = 0;
lookups = NetworkUtils.getAandAAAARecords(address, port);
//no result found, reset state and indicate "out of addresses"
if(lookups.length == 0)
{
lookups = null;
return false;
}
}
catch (ParseException e)
{
logger.error("Invalid address <" + address + ">", e);
return false;
}
}
//check if the available addresses are exhausted
if(lookupIndex >= lookups.length)
{
if(logger.isDebugEnabled())
logger.debug("No more addresses for " + account);
lookups = null;
return false;
}
//assign the next address and return lookup success
if(logger.isDebugEnabled())
logger.debug("Returning <" + socketAddress
+ "> as next address for " + account);
socketAddress = lookups[lookupIndex];
lookupIndex++;
return true;
}
/*
* (non-Javadoc)
*
* @see
* net.java.sip.communicator.impl.protocol.sip.net.ProxyConnection#reset()
*/
@Override
public void reset()
{
super.reset();
address = account.getAccountPropertyString(PROXY_ADDRESS);
port = account.getAccountPropertyInt(PROXY_PORT, PORT_5060);
transport = account.getAccountPropertyString(PREFERRED_TRANSPORT);
//check property sanity
if(!ProtocolProviderServiceSipImpl.isValidTransport(transport))
throw new IllegalArgumentException(
transport + " is not a valid SIP transport");
}
}

@ -0,0 +1,163 @@
package net.java.sip.communicator.impl.protocol.sip.net;
import java.net.*;
import java.util.*;
import net.java.sip.communicator.impl.protocol.sip.*;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.*;
/**
* Abstract class for the determining the address for the SIP proxy.
*
* @author Ingo Bauersachs
*/
public abstract class ProxyConnection
{
private List<String> returnedAddresses = new LinkedList<String>();
protected String transport;
protected InetSocketAddress socketAddress;
protected final SipAccountID account;
/**
* Creates a new instance of this class.
* @param account the account of this SIP protocol instance
*/
protected ProxyConnection(SipAccountID account)
{
this.account = account;
}
/**
* Gets the address to use for the next connection attempt.
* @return the address of the last lookup.
*/
public final InetSocketAddress getAddress()
{
if(socketAddress == null)
getNextAddress();
return socketAddress;
}
/**
* Gets the transport to use for the next connection attempt.
* @return the transport of the last lookup.
*/
public final String getTransport()
{
if(transport == null)
getNextAddress();
return transport;
}
/**
* In case we are using an outbound proxy this method returns
* a suitable string for use with Router.
* The method returns <tt>null</tt> otherwise.
*
* @return the string of our outbound proxy if we are using one and
* <tt>null</tt> otherwise.
*/
public final String getOutboundProxyString()
{
if(socketAddress == null)
if(!getNextAddress())
return null;
InetAddress proxyAddress = socketAddress.getAddress();
StringBuilder proxyStringBuffer
= new StringBuilder(proxyAddress.getHostAddress());
if(proxyAddress instanceof Inet6Address)
{
proxyStringBuffer.insert(0, '[');
proxyStringBuffer.append(']');
}
proxyStringBuffer.append(':');
proxyStringBuffer.append(socketAddress.getPort());
proxyStringBuffer.append('/');
proxyStringBuffer.append(transport);
return proxyStringBuffer.toString();
}
/**
* Compares an InetAddress against the active outbound proxy. The comparison
* is by reference, not equals.
*
* @param addressToTest The addres to test.
* @return True when the InetAddress is the same as the outbound proxy.
*/
public final boolean isSameInetAddress(InetAddress addressToTest)
{
// if the proxy is not yet initialized then this is not the provider
// that caused this comparison
if(socketAddress == null)
return false;
return addressToTest == socketAddress.getAddress();
}
/**
* Retrieves the next address to use from DNS. Duplicate results are
* suppressed.
*
* @return True if a new address is available through {@link #getAddress()},
* false if the last address was reached. A new lookup from scratch
* can be started by calling {@link #reset()}.
*/
public final boolean getNextAddress()
{
boolean result;
String key = null;
do
{
result = getNextAddressFromDns();
if(result && socketAddress != null)
{
key = getOutboundProxyString();
if(!returnedAddresses.contains(key))
{
returnedAddresses.add(key);
break;
}
}
}
while(result && returnedAddresses.contains(key));
return result;
}
/**
* Implementations must use this method to get the next address, but do not
* have to care about duplicate addresses.
*
* @return True when a further address was available.
*/
protected abstract boolean getNextAddressFromDns();
/**
* Resets the lookup to it's initial state. Overriders methods have to call
* this method through a super-call.
*/
public void reset()
{
returnedAddresses.clear();
}
/**
* Factory method to create a proxy connection based on the account settings
* of the protocol provider.
*
* @param pps the protocol provider that needs a SIP server connection.
* @return An instance of a derived class.
*/
public static ProxyConnection create(ProtocolProviderServiceSipImpl pps)
{
if (pps.getAccountID().getAccountPropertyBoolean(PROXY_AUTO_CONFIG,
true))
return new AutoProxyConnection((SipAccountID) pps.getAccountID(),
pps.getDefaultTransport());
else
return new ManualProxyConnection((SipAccountID) pps.getAccountID());
}
}

@ -190,7 +190,8 @@ private SSLSocketFactory getSSLSocketFactory(InetAddress address)
for (ProtocolProviderServiceSipImpl pps : ProtocolProviderServiceSipImpl
.getAllInstances())
{
if (pps.matchesInetAddress(address))
if (pps.getConnection() != null
&& pps.getConnection().isSameInetAddress(address))
{
provider = pps;
break;

@ -65,6 +65,7 @@ Import-Package: org.apache.log4j,
javax.xml.transform.dom,
javax.xml.transform.stream,
Export-Package: net.java.sip.communicator.impl.protocol.sip,
net.java.sip.communicator.impl.protocol.sip.net,
net.java.sip.communicator.impl.protocol.sip.xcap,
net.java.sip.communicator.impl.protocol.sip.xcap.utils,
net.java.sip.communicator.impl.protocol.sip.xcap.model,

@ -79,6 +79,9 @@ public void start(BundleContext context)
// xcap parsing tests
addTest(TestXCapParse.suite());
//proxy detection tests
addTestSuite(TestAutoProxyDetection.class);
//First test account installation so that the service that has
//been installed by it gets tested by the rest of the tests.
addTestSuite(TestAccountInstallation.class);

@ -0,0 +1,427 @@
/*
* 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.slick.protocol.sip;
import static org.easymock.EasyMock.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import net.java.sip.communicator.impl.protocol.sip.SipAccountID;
import net.java.sip.communicator.impl.protocol.sip.net.AutoProxyConnection;
import net.java.sip.communicator.util.SRVRecord;
import static net.java.sip.communicator.service.protocol.ProtocolProviderFactory.*;
import junit.framework.TestCase;
/**
* Tests all variations of automatic proxy detection through (simulated) DNS.
*
* @author Ingo Bauersachs
*/
public class TestAutoProxyDetection
extends TestCase
{
private static class TestedAutoProxyDetection extends AutoProxyConnection
{
public TestedAutoProxyDetection(SipAccountID account,
String defaultTransport)
{
super(account, defaultTransport);
}
@Override
public void setNetworkUtils(LocalNetworkUtils nu)
{
super.setNetworkUtils(nu);
}
public static class NetworkUtils extends LocalNetworkUtils
{
}
}
private SipAccountID account;
private TestedAutoProxyDetection.NetworkUtils nu;
private SRVRecord srv1;
private SRVRecord srv2;
private SRVRecord srv3;
private InetSocketAddress a1;
private InetSocketAddress a2;
private InetSocketAddress a3;
private InetSocketAddress a4;
private final static String DOMAIN = "example.com";
private InetAddress ia1;
private InetAddress ia2;
private InetAddress ia3;
private InetAddress ia4;
private TestedAutoProxyDetection apd;
public void setUp()
{
account = createMock(SipAccountID.class);
expect(account.getAccountPropertyString(USER_ID))
.andReturn("unit@" + DOMAIN);
replay(account);
nu = createMock(TestedAutoProxyDetection.NetworkUtils.class);
apd = new TestedAutoProxyDetection(account, "UDP");
apd.setNetworkUtils(nu);
srv1 = createMock(SRVRecord.class);
expect(srv1.getTarget()).andReturn("proxy1."+DOMAIN);
expect(srv1.getPort()).andReturn(5060);
srv2 = createMock(SRVRecord.class);
expect(srv2.getTarget()).andReturn("proxy2."+DOMAIN);
expect(srv2.getPort()).andReturn(5061);
srv3 = createMock(SRVRecord.class);
expect(srv3.getTarget()).andReturn("proxy3."+DOMAIN);
expect(srv3.getPort()).andReturn(5062);
try
{
ia1 = InetAddress.getByAddress("proxy1." + DOMAIN,
new byte[]{0x7f,0,0,1});
ia2 = InetAddress.getByAddress("proxy2." + DOMAIN,
new byte[]{0x7f,0,0,2});
ia3 = InetAddress.getByAddress("proxy3." + DOMAIN,
new byte[]{0x7f,0,0,3});
ia4 = InetAddress.getByAddress("proxy4." + DOMAIN,
new byte[]{0x7f,0,0,4});
}
catch (UnknownHostException e)
{
fail("unable to initialize: " + e.getMessage());
}
a1 = new InetSocketAddress(ia1, 5060);
a2 = new InetSocketAddress(ia2, 5061);
a3 = new InetSocketAddress(ia3, 5062);
a4 = new InetSocketAddress(ia4, 5063);
}
private void prepareOneNaptrOneSrv() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{
{"0", "udp", "_sip._udp." + DOMAIN}
});
expect(nu.getSRVRecords("_sip._udp."+DOMAIN))
.andReturn(new SRVRecord[]{ srv1 });
}
private void prepareOneNaptrTwoSrv() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{
{"0", "udp", "_sip._udp." + DOMAIN}
});
expect(nu.getSRVRecords("_sip._udp."+DOMAIN))
.andReturn(new SRVRecord[]{ srv1, srv2 });
}
public void testOneNaptrNoSrv() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{
{"0", "udp", "_sip._udp." + DOMAIN}
});
expect(nu.getSRVRecords("_sip._udp." + DOMAIN)).andReturn(null);
replay(nu);
assertFalse(apd.getNextAddress());
verify(account, nu);
}
public void testOneNaptrOneSrvOneA() throws ParseException
{
prepareOneNaptrOneSrv();
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
replay(nu, srv1);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1);
}
public void testOneNaptrOneSrvTwoA() throws ParseException
{
prepareOneNaptrOneSrv();
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1, a2});
replay(nu, srv1);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a2, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1);
}
//-----------------------
public void testOneNaptrTwoSrvOneA() throws ParseException
{
prepareOneNaptrTwoSrv();
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
expect(nu.getAandAAAARecords("proxy2." + DOMAIN, 5061))
.andReturn(new InetSocketAddress[]{a2});
replay(nu, srv1, srv2);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a2, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1, srv2);
}
public void testOneNaptrTwoSrvTwoA() throws ParseException
{
prepareOneNaptrTwoSrv();
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1, a2});
expect(nu.getAandAAAARecords("proxy2." + DOMAIN, 5061))
.andReturn(new InetSocketAddress[]{a3, a4});
replay(nu, srv1, srv2);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a2, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a3, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a4, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1, srv2);
}
//-------------------
public void testThreeNaptrOneSrvEachOneAEach() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{
{"0", "udp", "_sip._udp." + DOMAIN},
{"0", "tcp", "_sip._tcp." + DOMAIN},
{"0", "tls", "_sips._tcp." + DOMAIN}
});
expect(nu.getSRVRecords("_sip._udp."+DOMAIN))
.andReturn(new SRVRecord[]{ srv1 });
expect(nu.getSRVRecords("_sip._tcp."+DOMAIN))
.andReturn(new SRVRecord[]{ srv2 });
expect(nu.getSRVRecords("_sips._tcp."+DOMAIN))
.andReturn(new SRVRecord[]{ srv3 });
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
expect(nu.getAandAAAARecords("proxy2." + DOMAIN, 5061))
.andReturn(new InetSocketAddress[]{a1});
expect(nu.getAandAAAARecords("proxy3." + DOMAIN, 5062))
.andReturn(new InetSocketAddress[]{a1});
replay(nu, srv1, srv2, srv3);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a1, apd.getAddress());
assertEquals("TCP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a1, apd.getAddress());
assertEquals("TLS", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1, srv2, srv3);
}
//-----------------------
public void testNoSrvOneA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN)).andReturn(null);
expect(nu.getAandAAAARecords(DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
replay(nu);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu);
}
public void testOneSrvOneA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN))
.andReturn(new SRVRecord[]{srv1});
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
replay(nu, srv1);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1);
}
public void testOneSrvTwoA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN))
.andReturn(new SRVRecord[]{srv1});
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1, a2});
replay(nu, srv1);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a2, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1);
}
public void testTwoSrvOneA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN))
.andReturn(new SRVRecord[]{srv2});
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN))
.andReturn(new SRVRecord[]{srv1});
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
expect(nu.getAandAAAARecords("proxy2." + DOMAIN, 5061))
.andReturn(new InetSocketAddress[]{a2});
replay(nu, srv1, srv2);
assertEquals(a2, apd.getAddress());
assertEquals("TLS", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1, srv2);
}
//----------------------
public void testNoA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN)).andReturn(null);
expect(nu.getAandAAAARecords(DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{});
replay(nu);
assertFalse(apd.getNextAddress());
verify(account, nu);
}
public void testOneA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN)).andReturn(null);
expect(nu.getAandAAAARecords(DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
replay(nu);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu);
}
public void testTwoA() throws ParseException
{
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{});
expect(nu.getSRVRecords("sips", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "TCP", DOMAIN)).andReturn(null);
expect(nu.getSRVRecords("sip", "UDP", DOMAIN)).andReturn(null);
expect(nu.getAandAAAARecords(DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1, a2});
replay(nu);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertTrue(apd.getNextAddress());
assertEquals(a2, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu);
}
public void testNotReturningSameAddressTwice() throws ParseException
{
expect(srv1.getTarget()).andReturn("proxy1."+DOMAIN);
expect(srv1.getPort()).andReturn(5060);
expect(nu.getNAPTRRecords(DOMAIN)).andReturn(new String[][]{
{"0", "udp", "_sip._udp." + DOMAIN},
{"1", "udp", "_sip._udp." + DOMAIN}
});
expect(nu.getSRVRecords("_sip._udp."+DOMAIN)).andReturn(new SRVRecord[]{
srv1
});
expect(nu.getSRVRecords("_sip._udp."+DOMAIN)).andReturn(new SRVRecord[]{
srv1
});
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
expect(nu.getAandAAAARecords("proxy1." + DOMAIN, 5060))
.andReturn(new InetSocketAddress[]{a1});
replay(nu, srv1);
assertEquals(a1, apd.getAddress());
assertEquals("UDP", apd.getTransport());
assertFalse(apd.getNextAddress());
verify(account, nu, srv1);
}
}

@ -118,11 +118,7 @@ public static Test suite()
if(SipSlickFixture.onlineTestingDisabled)
{
TestSuite suite = new TestSuite();
//the only test around here that we could run without net
//connectivity
suite.addTest(
new TestOperationSetPresence(
"testSupportedStatusSetForCompleteness"));
//currently no tests without online connection
return suite;
}

@ -7,13 +7,15 @@ System-Bundle: yes
Import-Package: net.java.sip.communicator.service.configuration,
junit.framework,
org.osgi.framework,
org.w3c.dom;
javax.xml.namespace;
org.w3c.dom,
org.easymock,
javax.xml.namespace,
net.java.sip.communicator.util,
net.java.sip.communicator.util.xml,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.impl.protocol.sip,
net.java.sip.communicator.impl.protocol.sip.net,
net.java.sip.communicator.impl.protocol.sip.xcap,
net.java.sip.communicator.impl.protocol.sip.xcap.utils,
net.java.sip.communicator.impl.protocol.sip.xcap.model,

Loading…
Cancel
Save