mirror of https://github.com/sipwise/jitsi.git
parent
3b7274d9bb
commit
aaa147c435
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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());
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue