merge in jb-release history after reset to master
diff --git a/java/com/android/server/sip/SipService.java b/java/com/android/server/sip/SipService.java
index 97afc81..a477fd1 100644
--- a/java/com/android/server/sip/SipService.java
+++ b/java/com/android/server/sip/SipService.java
@@ -453,9 +453,8 @@
         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 @@
             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 @@
                 throws SipException {
             mSipGroup.onConnectivityChanged();
             if (connected) {
-                resetGroup(mLocalIp);
+                mSipGroup.reset();
                 if (mOpenedToReceiveCalls) openToReceiveCalls();
             } else {
                 // close mSipGroup but remember mOpenedToReceiveCalls
@@ -541,22 +519,6 @@
             }
         }
 
-        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/java/com/android/server/sip/SipSessionGroup.java b/java/com/android/server/sip/SipSessionGroup.java
index 877a0a4..6acd456 100644
--- a/java/com/android/server/sip/SipSessionGroup.java
+++ b/java/com/android/server/sip/SipSessionGroup.java
@@ -40,6 +40,7 @@
 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.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 @@
     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 @@
         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 @@
             mSipStack = null;
             mSipHelper = null;
         }
+        resetExternalAddress();
     }
 
     public synchronized boolean isClosed() {
@@ -257,17 +277,6 @@
         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);
     }