From 2dd9134c6b2da47f4816bc0f72a0e4924aca4f84 Mon Sep 17 00:00:00 2001 From: Chia-chi Yeh Date: Wed, 4 Apr 2012 13:04:26 -0700 Subject: SIP: push the logic of finding local address down to SipSessionGroup. This allows different accounts binding on different IP addresses, such as one on IPv4 and another on IPv6. Bug: 4169057 Change-Id: I0bb36669394c281330091673fa338adea8f782cd --- voip/java/com/android/server/sip/SipService.java | 44 +-------- .../com/android/server/sip/SipSessionGroup.java | 105 +++++++++++---------- 2 files changed, 60 insertions(+), 89 deletions(-) diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java index 97afc81..a477fd1 100644 --- a/voip/java/com/android/server/sip/SipService.java +++ b/voip/java/com/android/server/sip/SipService.java @@ -453,9 +453,8 @@ public final class SipService extends ISipService.Stub { public SipSessionGroupExt(SipProfile localProfile, PendingIntent incomingCallPendingIntent, ISipSessionListener listener) throws SipException { - String password = localProfile.getPassword(); - SipProfile p = duplicate(localProfile); - mSipGroup = createSipSessionGroup(mLocalIp, p, password); + mSipGroup = new SipSessionGroup(duplicate(localProfile), + localProfile.getPassword(), mTimer, mMyWakeLock); mIncomingCallPendingIntent = incomingCallPendingIntent; mAutoRegistration.setListener(listener); } @@ -478,27 +477,6 @@ public final class SipService extends ISipService.Stub { mSipGroup.setWakeupTimer(timer); } - // network connectivity is tricky because network can be disconnected - // at any instant so need to deal with exceptions carefully even when - // you think you are connected - private SipSessionGroup createSipSessionGroup(String localIp, - SipProfile localProfile, String password) throws SipException { - try { - return new SipSessionGroup(localIp, localProfile, password, - mTimer, mMyWakeLock); - } catch (IOException e) { - // network disconnected - Log.w(TAG, "createSipSessionGroup(): network disconnected?"); - if (localIp != null) { - return createSipSessionGroup(null, localProfile, password); - } else { - // recursive - Log.wtf(TAG, "impossible! recursive!"); - throw new RuntimeException("createSipSessionGroup"); - } - } - } - private SipProfile duplicate(SipProfile p) { try { return new SipProfile.Builder(p).setPassword("*").build(); @@ -530,7 +508,7 @@ public final class SipService extends ISipService.Stub { throws SipException { mSipGroup.onConnectivityChanged(); if (connected) { - resetGroup(mLocalIp); + mSipGroup.reset(); if (mOpenedToReceiveCalls) openToReceiveCalls(); } else { // close mSipGroup but remember mOpenedToReceiveCalls @@ -541,22 +519,6 @@ public final class SipService extends ISipService.Stub { } } - private void resetGroup(String localIp) throws SipException { - try { - mSipGroup.reset(localIp); - } catch (IOException e) { - // network disconnected - Log.w(TAG, "resetGroup(): network disconnected?"); - if (localIp != null) { - resetGroup(null); // reset w/o local IP - } else { - // recursive - Log.wtf(TAG, "impossible!"); - throw new RuntimeException("resetGroup"); - } - } - } - public void close() { mOpenedToReceiveCalls = false; mSipGroup.close(); diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 877a0a4..6acd456 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -40,6 +40,7 @@ import android.util.Log; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.DatagramSocket; +import java.net.InetAddress; import java.net.UnknownHostException; import java.text.ParseException; import java.util.Collection; @@ -47,13 +48,11 @@ import java.util.EventObject; import java.util.HashMap; import java.util.Map; import java.util.Properties; -import java.util.TooManyListenersException; import javax.sip.ClientTransaction; import javax.sip.Dialog; import javax.sip.DialogTerminatedEvent; import javax.sip.IOExceptionEvent; -import javax.sip.InvalidArgumentException; import javax.sip.ListeningPoint; import javax.sip.ObjectInUseException; import javax.sip.RequestEvent; @@ -132,18 +131,17 @@ class SipSessionGroup implements SipListener { private int mExternalPort; /** - * @param myself the local profile with password crossed out + * @param profile the local profile with password crossed out * @param password the password of the profile * @throws IOException if cannot assign requested address */ - public SipSessionGroup(String localIp, SipProfile myself, String password, - SipWakeupTimer timer, SipWakeLock wakeLock) throws SipException, - IOException { - mLocalProfile = myself; + public SipSessionGroup(SipProfile profile, String password, + SipWakeupTimer timer, SipWakeLock wakeLock) throws SipException { + mLocalProfile = profile; mPassword = password; mWakeupTimer = timer; mWakeLock = wakeLock; - reset(localIp); + reset(); } // TODO: remove this method once SipWakeupTimer can better handle variety @@ -152,43 +150,64 @@ class SipSessionGroup implements SipListener { mWakeupTimer = timer; } - synchronized void reset(String localIp) throws SipException, IOException { - mLocalIp = localIp; - if (localIp == null) return; - - SipProfile myself = mLocalProfile; - SipFactory sipFactory = SipFactory.getInstance(); + synchronized void reset() throws SipException { Properties properties = new Properties(); + + String protocol = mLocalProfile.getProtocol(); + int port = mLocalProfile.getPort(); + String server = mLocalProfile.getProxyAddress(); + + if (!TextUtils.isEmpty(server)) { + properties.setProperty("javax.sip.OUTBOUND_PROXY", + server + ':' + port + '/' + protocol); + } else { + server = mLocalProfile.getSipDomain(); + } + if (server.startsWith("[") && server.endsWith("]")) { + server = server.substring(1, server.length() - 1); + } + + String local = null; + try { + for (InetAddress remote : InetAddress.getAllByName(server)) { + DatagramSocket socket = new DatagramSocket(); + socket.connect(remote, port); + if (socket.isConnected()) { + local = socket.getLocalAddress().getHostAddress(); + port = socket.getLocalPort(); + socket.close(); + break; + } + socket.close(); + } + } catch (Exception e) { + // ignore. + } + if (local == null) { + // We are unable to reach the server. Just bail out. + return; + } + + close(); + mLocalIp = local; + properties.setProperty("javax.sip.STACK_NAME", getStackName()); properties.setProperty( "gov.nist.javax.sip.THREAD_POOL_SIZE", THREAD_POOL_SIZE); - String outboundProxy = myself.getProxyAddress(); - if (!TextUtils.isEmpty(outboundProxy)) { - Log.v(TAG, "outboundProxy is " + outboundProxy); - properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy - + ":" + myself.getPort() + "/" + myself.getProtocol()); - } - SipStack stack = mSipStack = sipFactory.createSipStack(properties); - + mSipStack = SipFactory.getInstance().createSipStack(properties); try { - SipProvider provider = stack.createSipProvider( - stack.createListeningPoint(localIp, allocateLocalPort(), - myself.getProtocol())); + SipProvider provider = mSipStack.createSipProvider( + mSipStack.createListeningPoint(local, port, protocol)); provider.addSipListener(this); - mSipHelper = new SipHelper(stack, provider); - } catch (InvalidArgumentException e) { - throw new IOException(e.getMessage()); - } catch (TooManyListenersException e) { - // must never happen - throw new SipException("SipSessionGroup constructor", e); + mSipHelper = new SipHelper(mSipStack, provider); + } catch (SipException e) { + throw e; + } catch (Exception e) { + throw new SipException("failed to initialize SIP stack", e); } - Log.d(TAG, " start stack for " + myself.getUriString()); - stack.start(); - - mCallReceiverSession = null; - mSessionMap.clear(); - resetExternalAddress(); + Log.d(TAG, " start stack for " + mLocalProfile.getUriString()); + mSipStack.start(); } synchronized void onConnectivityChanged() { @@ -234,6 +253,7 @@ class SipSessionGroup implements SipListener { mSipStack = null; mSipHelper = null; } + resetExternalAddress(); } public synchronized boolean isClosed() { @@ -257,17 +277,6 @@ class SipSessionGroup implements SipListener { return (isClosed() ? null : new SipSessionImpl(listener)); } - private static int allocateLocalPort() throws SipException { - try { - DatagramSocket s = new DatagramSocket(); - int localPort = s.getLocalPort(); - s.close(); - return localPort; - } catch (IOException e) { - throw new SipException("allocateLocalPort()", e); - } - } - synchronized boolean containsSession(String callId) { return mSessionMap.containsKey(callId); } -- cgit v1.1