4040import java .io .IOException ;
4141import java .io .UnsupportedEncodingException ;
4242import java .net .DatagramSocket ;
43+ import java .net .InetAddress ;
4344import java .net .UnknownHostException ;
4445import java .text .ParseException ;
4546import java .util .Collection ;
4647import java .util .EventObject ;
4748import java .util .HashMap ;
4849import java .util .Map ;
4950import java .util .Properties ;
50- import java .util .TooManyListenersException ;
5151
5252import javax .sip .ClientTransaction ;
5353import javax .sip .Dialog ;
5454import javax .sip .DialogTerminatedEvent ;
5555import javax .sip .IOExceptionEvent ;
56- import javax .sip .InvalidArgumentException ;
5756import javax .sip .ListeningPoint ;
5857import javax .sip .ObjectInUseException ;
5958import javax .sip .RequestEvent ;
@@ -132,18 +131,17 @@ class SipSessionGroup implements SipListener {
132131 private int mExternalPort ;
133132
134133 /**
135- * @param myself the local profile with password crossed out
134+ * @param profile the local profile with password crossed out
136135 * @param password the password of the profile
137136 * @throws IOException if cannot assign requested address
138137 */
139- public SipSessionGroup (String localIp , SipProfile myself , String password ,
140- SipWakeupTimer timer , SipWakeLock wakeLock ) throws SipException ,
141- IOException {
142- mLocalProfile = myself ;
138+ public SipSessionGroup (SipProfile profile , String password ,
139+ SipWakeupTimer timer , SipWakeLock wakeLock ) throws SipException {
140+ mLocalProfile = profile ;
143141 mPassword = password ;
144142 mWakeupTimer = timer ;
145143 mWakeLock = wakeLock ;
146- reset (localIp );
144+ reset ();
147145 }
148146
149147 // TODO: remove this method once SipWakeupTimer can better handle variety
@@ -152,43 +150,64 @@ void setWakeupTimer(SipWakeupTimer timer) {
152150 mWakeupTimer = timer ;
153151 }
154152
155- synchronized void reset (String localIp ) throws SipException , IOException {
156- mLocalIp = localIp ;
157- if (localIp == null ) return ;
158-
159- SipProfile myself = mLocalProfile ;
160- SipFactory sipFactory = SipFactory .getInstance ();
153+ synchronized void reset () throws SipException {
161154 Properties properties = new Properties ();
155+
156+ String protocol = mLocalProfile .getProtocol ();
157+ int port = mLocalProfile .getPort ();
158+ String server = mLocalProfile .getProxyAddress ();
159+
160+ if (!TextUtils .isEmpty (server )) {
161+ properties .setProperty ("javax.sip.OUTBOUND_PROXY" ,
162+ server + ':' + port + '/' + protocol );
163+ } else {
164+ server = mLocalProfile .getSipDomain ();
165+ }
166+ if (server .startsWith ("[" ) && server .endsWith ("]" )) {
167+ server = server .substring (1 , server .length () - 1 );
168+ }
169+
170+ String local = null ;
171+ try {
172+ for (InetAddress remote : InetAddress .getAllByName (server )) {
173+ DatagramSocket socket = new DatagramSocket ();
174+ socket .connect (remote , port );
175+ if (socket .isConnected ()) {
176+ local = socket .getLocalAddress ().getHostAddress ();
177+ port = socket .getLocalPort ();
178+ socket .close ();
179+ break ;
180+ }
181+ socket .close ();
182+ }
183+ } catch (Exception e ) {
184+ // ignore.
185+ }
186+ if (local == null ) {
187+ // We are unable to reach the server. Just bail out.
188+ return ;
189+ }
190+
191+ close ();
192+ mLocalIp = local ;
193+
162194 properties .setProperty ("javax.sip.STACK_NAME" , getStackName ());
163195 properties .setProperty (
164196 "gov.nist.javax.sip.THREAD_POOL_SIZE" , THREAD_POOL_SIZE );
165- String outboundProxy = myself .getProxyAddress ();
166- if (!TextUtils .isEmpty (outboundProxy )) {
167- Log .v (TAG , "outboundProxy is " + outboundProxy );
168- properties .setProperty ("javax.sip.OUTBOUND_PROXY" , outboundProxy
169- + ":" + myself .getPort () + "/" + myself .getProtocol ());
170- }
171- SipStack stack = mSipStack = sipFactory .createSipStack (properties );
172-
197+ mSipStack = SipFactory .getInstance ().createSipStack (properties );
173198 try {
174- SipProvider provider = stack .createSipProvider (
175- stack .createListeningPoint (localIp , allocateLocalPort (),
176- myself .getProtocol ()));
199+ SipProvider provider = mSipStack .createSipProvider (
200+ mSipStack .createListeningPoint (local , port , protocol ));
177201 provider .addSipListener (this );
178- mSipHelper = new SipHelper (stack , provider );
179- } catch (InvalidArgumentException e ) {
180- throw new IOException (e .getMessage ());
181- } catch (TooManyListenersException e ) {
182- // must never happen
183- throw new SipException ("SipSessionGroup constructor" , e );
202+ mSipHelper = new SipHelper (mSipStack , provider );
203+ } catch (SipException e ) {
204+ throw e ;
205+ } catch (Exception e ) {
206+ throw new SipException ("failed to initialize SIP stack" , e );
184207 }
185- Log .d (TAG , " start stack for " + myself .getUriString ());
186- stack .start ();
187-
188- mCallReceiverSession = null ;
189- mSessionMap .clear ();
190208
191- resetExternalAddress ();
209+ Log .d (TAG , " start stack for " + mLocalProfile .getUriString ());
210+ mSipStack .start ();
192211 }
193212
194213 synchronized void onConnectivityChanged () {
@@ -234,6 +253,7 @@ public synchronized void close() {
234253 mSipStack = null ;
235254 mSipHelper = null ;
236255 }
256+ resetExternalAddress ();
237257 }
238258
239259 public synchronized boolean isClosed () {
@@ -257,17 +277,6 @@ public ISipSession createSession(ISipSessionListener listener) {
257277 return (isClosed () ? null : new SipSessionImpl (listener ));
258278 }
259279
260- private static int allocateLocalPort () throws SipException {
261- try {
262- DatagramSocket s = new DatagramSocket ();
263- int localPort = s .getLocalPort ();
264- s .close ();
265- return localPort ;
266- } catch (IOException e ) {
267- throw new SipException ("allocateLocalPort()" , e );
268- }
269- }
270-
271280 synchronized boolean containsSession (String callId ) {
272281 return mSessionMap .containsKey (callId );
273282 }
0 commit comments