Index: /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj/project.pbxproj	(revision 5649)
@@ -40,4 +40,6 @@
 		3AF253001EFBD15E00213893 /* libyuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF252FF1EFBD15E00213893 /* libyuv.a */; };
 		3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AF253011EFBD36E00213893 /* VideoToolbox.framework */; };
+		7485A6AF1F09AAE500122F1A /* Reachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 7485A6AE1F09AAE500122F1A /* Reachability.m */; };
+		7485A6B11F09B2D500122F1A /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */; };
 		E5E991E61B67A45500017E67 /* libg7221codec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D41B67A45500017E67 /* libg7221codec.a */; };
 		E5E991E71B67A45500017E67 /* libgsmcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5E991D51B67A45500017E67 /* libgsmcodec.a */; };
@@ -98,4 +100,8 @@
 		3AF252FF1EFBD15E00213893 /* libyuv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libyuv.a; sourceTree = "<group>"; };
 		3AF253011EFBD36E00213893 /* VideoToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = VideoToolbox.framework; path = System/Library/Frameworks/VideoToolbox.framework; sourceTree = SDKROOT; };
+		741C73BA1F0E64AF00887FB6 /* libopenh264.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopenh264.a; path = "../../../../../../../../../../openh264-1.6.0/lib_armv7/lib/libopenh264.a"; sourceTree = "<group>"; };
+		7485A6AD1F09AAE500122F1A /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reachability.h; sourceTree = "<group>"; };
+		7485A6AE1F09AAE500122F1A /* Reachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Reachability.m; sourceTree = "<group>"; };
+		7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
 		E5E991D41B67A45500017E67 /* libg7221codec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libg7221codec.a; sourceTree = "<group>"; };
 		E5E991D51B67A45500017E67 /* libgsmcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgsmcodec.a; sourceTree = "<group>"; };
@@ -123,4 +129,5 @@
 			buildActionMask = 2147483647;
 			files = (
+				7485A6B11F09B2D500122F1A /* SystemConfiguration.framework in Frameworks */,
 				3AF253021EFBD36E00213893 /* VideoToolbox.framework in Frameworks */,
 				3AB0EC581DA76B39008A0F62 /* libc++.tbd in Frameworks */,
@@ -197,4 +204,6 @@
 			isa = PBXGroup;
 			children = (
+				741C73BA1F0E64AF00887FB6 /* libopenh264.a */,
+				7485A6B01F09B2D500122F1A /* SystemConfiguration.framework */,
 				3AF253011EFBD36E00213893 /* VideoToolbox.framework */,
 				3AB0EC571DA76B39008A0F62 /* libc++.tbd */,
@@ -224,4 +233,6 @@
 				3AF0582016F050780046B835 /* ipjsuaViewController.h */,
 				3AF0582116F050780046B835 /* ipjsuaViewController.m */,
+				7485A6AD1F09AAE500122F1A /* Reachability.h */,
+				7485A6AE1F09AAE500122F1A /* Reachability.m */,
 				3AF0582316F050780046B835 /* ipjsuaViewController_iPhone.xib */,
 				3AF0582616F050780046B835 /* ipjsuaViewController_iPad.xib */,
@@ -354,4 +365,5 @@
 				3ADCCD2F172E40120007BE8E /* pjsua_app_config.c in Sources */,
 				3ADCCD30172E40120007BE8E /* pjsua_app_legacy.c in Sources */,
+				7485A6AF1F09AAE500122F1A /* Reachability.m in Sources */,
 				3ADCCD31172E40120007BE8E /* pjsua_app.c in Sources */,
 			);
Index: /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h	(revision 5649)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.h	(revision 5649)
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sampleâs licensing information
+ 
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <Foundation/Foundation.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+#import <netinet/in.h>
+
+
+typedef enum : NSInteger {
+	NotReachable = 0,
+	ReachableViaWiFi,
+	ReachableViaWWAN
+} NetworkStatus;
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
+
+
+extern NSString *kReachabilityChangedNotification;
+
+
+@interface Reachability : NSObject
+
+/*!
+ * Use to check the reachability of a given host name.
+ */
++ (instancetype)reachabilityWithHostName:(NSString *)hostName;
+
+/*!
+ * Use to check the reachability of a given IP address.
+ */
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress;
+
+/*!
+ * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
+ */
++ (instancetype)reachabilityForInternetConnection;
+
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi;
+
+/*!
+ * Start listening for reachability notifications on the current run loop.
+ */
+- (BOOL)startNotifier;
+- (void)stopNotifier;
+
+- (NetworkStatus)currentReachabilityStatus;
+
+/*!
+ * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
+ */
+- (BOOL)connectionRequired;
+
+@end
+
+
Index: /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m	(revision 5649)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/Reachability.m	(revision 5649)
@@ -0,0 +1,242 @@
+/*
+ Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ See LICENSE.txt for this sampleâs licensing information
+ 
+ Abstract:
+ Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
+ */
+
+#import <arpa/inet.h>
+#import <ifaddrs.h>
+#import <netdb.h>
+#import <sys/socket.h>
+#import <netinet/in.h>
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#import "Reachability.h"
+
+#pragma mark IPv6 Support
+//Reachability fully support IPv6.  For full details, see ReadMe.md.
+
+
+NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";
+
+
+#pragma mark - Supporting functions
+
+#define kShouldPrintReachabilityFlags 1
+
+static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
+{
+#if kShouldPrintReachabilityFlags
+
+    NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
+          (flags & kSCNetworkReachabilityFlagsIsWWAN)				? 'W' : '-',
+          (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
+
+          (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
+          (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+          (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
+          (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
+          comment
+          );
+#endif
+}
+
+
+static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
+{
+#pragma unused (target, flags)
+	NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
+	NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");
+
+    Reachability* noteObject = (__bridge Reachability *)info;
+    // Post a notification to notify the client that the network reachability changed.
+    [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
+}
+
+
+#pragma mark - Reachability implementation
+
+@implementation Reachability
+{
+	SCNetworkReachabilityRef _reachabilityRef;
+}
+
++ (instancetype)reachabilityWithHostName:(NSString *)hostName
+{
+	Reachability* returnValue = NULL;
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
+	if (reachability != NULL)
+	{
+		returnValue= [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
+        }
+	}
+	return returnValue;
+}
+
+
++ (instancetype)reachabilityWithAddress:(const struct sockaddr *)hostAddress
+{
+	SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, hostAddress);
+
+	Reachability* returnValue = NULL;
+
+	if (reachability != NULL)
+	{
+		returnValue = [[self alloc] init];
+		if (returnValue != NULL)
+		{
+			returnValue->_reachabilityRef = reachability;
+		}
+        else {
+            CFRelease(reachability);
+        }
+	}
+	return returnValue;
+}
+
+
++ (instancetype)reachabilityForInternetConnection
+{
+	struct sockaddr_in zeroAddress;
+	bzero(&zeroAddress, sizeof(zeroAddress));
+	zeroAddress.sin_len = sizeof(zeroAddress);
+	zeroAddress.sin_family = AF_INET;
+    
+    return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
+}
+
+#pragma mark reachabilityForLocalWiFi
+//reachabilityForLocalWiFi has been removed from the sample.  See ReadMe.md for more information.
+//+ (instancetype)reachabilityForLocalWiFi
+
+
+
+#pragma mark - Start and stop notifier
+
+- (BOOL)startNotifier
+{
+	BOOL returnValue = NO;
+	SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
+
+	if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
+	{
+		if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
+		{
+			returnValue = YES;
+		}
+	}
+    
+	return returnValue;
+}
+
+
+- (void)stopNotifier
+{
+	if (_reachabilityRef != NULL)
+	{
+		SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+	}
+}
+
+
+- (void)dealloc
+{
+	[self stopNotifier];
+	if (_reachabilityRef != NULL)
+	{
+		CFRelease(_reachabilityRef);
+	}
+}
+
+
+#pragma mark - Network Flag Handling
+
+- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
+{
+	PrintReachabilityFlags(flags, "networkStatusForFlags");
+	if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
+	{
+		// The target host is not reachable.
+		return NotReachable;
+	}
+
+    NetworkStatus returnValue = NotReachable;
+
+	if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
+	{
+		/*
+         If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
+         */
+		returnValue = ReachableViaWiFi;
+	}
+
+	if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
+        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
+	{
+        /*
+         ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
+         */
+
+        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
+        {
+            /*
+             ... and no [user] intervention is needed...
+             */
+            returnValue = ReachableViaWiFi;
+        }
+    }
+
+	if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
+	{
+		/*
+         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
+         */
+		returnValue = ReachableViaWWAN;
+	}
+    
+	return returnValue;
+}
+
+
+- (BOOL)connectionRequired
+{
+	NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
+	SCNetworkReachabilityFlags flags;
+
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+		return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
+	}
+
+    return NO;
+}
+
+
+- (NetworkStatus)currentReachabilityStatus
+{
+	NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
+	NetworkStatus returnValue = NotReachable;
+	SCNetworkReachabilityFlags flags;
+    
+	if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
+	{
+        returnValue = [self networkStatusForFlags:flags];
+	}
+    
+	return returnValue;
+}
+
+
+@end
Index: /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/ios/ipjsua/ipjsuaAppDelegate.m	(revision 5649)
@@ -28,4 +28,5 @@
 
 #import "ipjsuaViewController.h"
+#import "Reachability.h"
 
 @implementation ipjsuaAppDelegate
@@ -40,4 +41,44 @@
 static char           **restartArgv;
 static int              restartArgc;
+Reachability            *internetReach;
+
+- (void) updateWithReachability: (Reachability *)curReach
+{
+    NetworkStatus netStatus = [curReach currentReachabilityStatus];
+    BOOL connectionRequired = [curReach connectionRequired];
+    switch (netStatus) {
+        case NotReachable:
+            PJ_LOG(3,("", "Access Not Available.."));
+            connectionRequired= NO;
+            break;
+        case ReachableViaWiFi:
+            PJ_LOG(3,("", "Reachable WiFi.."));
+            break;
+        case ReachableViaWWAN:
+            PJ_LOG(3,("", "Reachable WWAN.."));
+        break;
+    }
+    if (connectionRequired) {
+        PJ_LOG(3,("", "Connection Required"));
+    }
+}
+
+/* Called by Reachability whenever status changes. */
+- (void)reachabilityChanged: (NSNotification *)note
+{
+    Reachability* curReach = [note object];
+    NSParameterAssert([curReach isKindOfClass: [Reachability class]]);
+    PJ_LOG(3,("", "reachability changed.."));
+    [self updateWithReachability: curReach];
+    
+    if ([curReach currentReachabilityStatus] != NotReachable &&
+        ![curReach connectionRequired])
+    {
+        pjsua_ip_change_param param;
+        pjsua_ip_change_param_default(&param);
+        pjsua_handle_ip_change(&param);
+    }
+}
+
 
 void displayLog(const char *msg, int len)
@@ -155,4 +196,15 @@
     self.window.rootViewController = self.viewController;
     [self.window makeKeyAndVisible];
+    
+    /* Observe the kNetworkReachabilityChangedNotification. When that
+     * notification is posted, the method "reachabilityChanged" will be called.
+     */
+    [[NSNotificationCenter defaultCenter] addObserver: self
+          selector: @selector(reachabilityChanged:)
+          name: kReachabilityChangedNotification object: nil];
+    
+    internetReach = [Reachability reachabilityForInternetConnection];
+    [internetReach startNotifier];
+    [self updateWithReachability: internetReach];
     
     app = self;
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_cli.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_cli.c	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app_cli.c	(revision 5649)
@@ -39,4 +39,5 @@
 #define CMD_QUIT		    110
 #define CMD_RESTART		    120
+#define CMD_HANDLE_IP_CHANGE	    130
 
 /* call level 2 command */
@@ -2584,4 +2585,16 @@
     /* Invoke CLI stop callback (defined in pjsua_app.c) */
     cli_on_stopped(PJ_FALSE, 0, NULL);
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t cmd_ip_change_handler(pj_cli_cmd_val *cval)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pjsua_ip_change_param param;
+    PJ_UNUSED_ARG(cval);
+
+    pjsua_ip_change_param_default(&param);
+    pjsua_handle_ip_change(&param);    
 
     return PJ_SUCCESS;
@@ -3069,4 +3082,7 @@
 	"</CMD>";
 
+    char* ip_change_command =
+	"<CMD name='ip_change' id='130' desc='Handle IP change'/>";
+
     pj_status_t status;
     pj_str_t sleep_xml = pj_str(sleep_command);
@@ -3074,4 +3090,5 @@
     pj_str_t shutdown_xml = pj_str(shutdown_command);
     pj_str_t restart_xml = pj_str(restart_command);
+    pj_str_t ip_change_xml = pj_str(ip_change_command);
 
     status = pj_cli_add_cmd_from_xml(c, NULL,
@@ -3098,4 +3115,11 @@
 				     NULL, NULL);
 
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_cli_add_cmd_from_xml(c, NULL,
+				     &ip_change_xml, cmd_ip_change_handler,
+				     NULL, NULL);
+
     return status;
 }
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MainActivity.java	(revision 5649)
@@ -19,4 +19,5 @@
 package org.pjsip.pjsua2.app;
 
+import android.content.IntentFilter;
 import android.os.Bundle;
 import android.os.Handler;
@@ -27,4 +28,6 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -37,4 +40,6 @@
 import android.widget.SimpleAdapter;
 import android.widget.TextView;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
 
 import java.util.ArrayList;
@@ -51,4 +56,6 @@
     public static MyAccount account = null;
     public static AccountConfig accCfg = null;
+    public static MyBroadcastReceiver receiver = null;
+    public static IntentFilter intentFilter = null;
 
     private ListView buddyListView;
@@ -66,4 +73,37 @@
 	public final static int BUDDY_STATE = 4;
 	public final static int CALL_MEDIA_STATE = 5;
+	public final static int CHANGE_NETWORK = 6;
+    }
+
+    private class MyBroadcastReceiver extends BroadcastReceiver {
+	private String conn_name = "";
+
+	@Override
+	public void onReceive(Context context, Intent intent) {
+	    if (isNetworkChange(context))
+		notifyChangeNetwork();
+	}
+
+	private boolean isNetworkChange(Context context) {
+	    boolean network_changed = false;
+	    ConnectivityManager connectivity_mgr =
+		((ConnectivityManager)context.getSystemService(
+		    				 Context.CONNECTIVITY_SERVICE));
+
+	    NetworkInfo net_info = connectivity_mgr.getActiveNetworkInfo();
+	    if(net_info != null && net_info.isConnectedOrConnecting() &&
+	       !conn_name.equalsIgnoreCase(""))
+	    {
+		String new_con = net_info.getExtraInfo();
+		if (new_con != null && !new_con.equalsIgnoreCase(conn_name))
+		    network_changed = true;
+
+		conn_name = (new_con == null)?"":new_con;
+	    } else {
+		if (conn_name.equalsIgnoreCase(""))
+		    conn_name = net_info.getExtraInfo();
+	    }
+	    return network_changed;
+	}
     }
 
@@ -144,5 +184,10 @@
 	    }
 	);
-
+	if (receiver == null) {
+	    receiver = new MyBroadcastReceiver();
+	    intentFilter = new IntentFilter(
+			               ConnectivityManager.CONNECTIVITY_ACTION);
+	    registerReceiver(receiver, intentFilter);
+	}
     }
 
@@ -264,4 +309,6 @@
 	    showCallActivity();
 
+	} else if (m.what == MSG_TYPE.CHANGE_NETWORK) {
+	    app.handleNetworkChange();
 	} else {
 
@@ -577,4 +624,10 @@
     }
 
+    public void notifyChangeNetwork()
+    {
+	Message m = Message.obtain(handler, MSG_TYPE.CHANGE_NETWORK, null);
+	m.sendToTarget();
+    }
+
     /* === end of MyAppObserver ==== */
 
Index: /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/android/app/src/main/java/org/pjsip/pjsua2/app/MyApp.java	(revision 5649)
@@ -34,4 +34,5 @@
     abstract void notifyCallMediaState(MyCall call);
     abstract void notifyBuddyState(MyBuddy buddy);
+    abstract void notifyChangeNetwork();
 }
 
@@ -535,4 +536,15 @@
     }
 
+    public void handleNetworkChange()
+    {
+	try{
+	    System.out.println("Network change detected");
+	    IpChangeParam changeParam = new IpChangeParam();
+	    ep.handleIpChange(changeParam);
+	} catch (Exception e) {
+	    System.out.println(e);
+	}
+    }
+
     public void deinit()
     {
Index: /pjproject/trunk/pjsip-apps/src/swig/java/sample.java
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/java/sample.java	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/swig/java/sample.java	(revision 5649)
@@ -64,4 +64,7 @@
 	@Override
 	public void notifyBuddyState(MyBuddy buddy) {}	
+
+	@Override
+	public void notifyChangeNetwork() {}
 }
 
Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.i
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.i	(revision 5649)
@@ -176,2 +176,4 @@
 typedef enum pjsua_snd_dev_mode {PJSUA_SND_DEV_SPEAKER_ONLY = 1, PJSUA_SND_DEV_NO_IMMEDIATE_OPEN = 2} pjsua_snd_dev_mode;
 
+typedef enum pjsua_ip_change_op {PJSUA_IP_CHANGE_OP_NULL, PJSUA_IP_CHANGE_OP_RESTART_LIS, PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP, PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT, PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS, PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS} pjsua_ip_change_op;
+
Index: /pjproject/trunk/pjsip-apps/src/swig/symbols.lst
===================================================================
--- /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5648)
+++ /pjproject/trunk/pjsip-apps/src/swig/symbols.lst	(revision 5649)
@@ -34,3 +34,3 @@
 pjsip-ua/sip_inv.h              pjsip_inv_state
 
-pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode
+pjsua-lib/pjsua.h		pjsua_invalid_id_const_ pjsua_state pjsua_stun_use pjsua_call_hold_type pjsua_acc_id pjsua_destroy_flag pjsua_100rel_use pjsua_sip_timer_use pjsua_ipv6_use pjsua_nat64_opt pjsua_buddy_status pjsua_call_media_status pjsua_vid_win_id pjsua_call_id pjsua_med_tp_st pjsua_call_vid_strm_op pjsua_vid_req_keyframe_method pjsua_call_flag pjsua_create_media_transport_flag pjsua_snd_dev_mode pjsua_ip_change_op
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transport_tcp.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transport_tcp.h	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transport_tcp.h	(revision 5649)
@@ -226,4 +226,55 @@
 PJ_DECL(pj_sock_t) pjsip_tcp_transport_get_socket(pjsip_transport *transport);
 
+/**
+ * Start the TCP listener, if the listener is not started yet. This is useful
+ * to start the listener manually, if listener was not started when 
+ * PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER is set to 0. 
+ *
+ * @param factory	The SIP TCP transport factory.
+ *
+ * @param local		The address where the listener should be bound to. 
+ *			Both IP interface address and port fields are optional.
+ *			If IP interface address is not specified, socket
+ *			will be bound to PJ_INADDR_ANY. If port is not
+ *			specified, socket will be bound to any port
+ *			selected by the operating system.
+ *
+ * @param a_name	The published address for the listener. 
+ *			If this argument is NULL, then the bound address will 
+ *			be used as the published address.
+ *
+ * @return		PJ_SUCCESS when the listener has been successfully
+ *			started.
+ */
+PJ_DECL(pj_status_t) pjsip_tcp_transport_lis_start(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name);
+
+/**
+ * Restart the TCP listener. This will close the listener socket and recreate
+ * the socket based on the config used when starting the transport.
+ *
+ * @param factory	The SIP TCP transport factory.
+ * 
+ * @param local		The address where the listener should be bound to.
+ *			Both IP interface address and port fields are optional.
+ *			If IP interface address is not specified, socket
+ *			will be bound to PJ_INADDR_ANY. If port is not
+ *			specified, socket will be bound to any port
+ *			selected by the operating system.
+ *
+ * @param a_name	The published address for the listener. 
+ *			If this argument is NULL, then the bound address will
+ *			be used as the published address.
+ *
+ * @return		PJ_SUCCESS when the listener has been successfully 
+ *			restarted.
+ *
+ */
+PJ_DECL(pj_status_t) pjsip_tcp_transport_restart(pjsip_tpfactory *factory, 
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name);
+
+
 PJ_END_DECL
 
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transport_tls.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transport_tls.h	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transport_tls.h	(revision 5649)
@@ -430,9 +430,60 @@
  */
 PJ_DECL(pj_status_t) pjsip_tls_transport_start2(pjsip_endpoint *endpt,
- 					        const pjsip_tls_setting *opt,
-					        const pj_sockaddr *local,
-					        const pjsip_host_port *a_name,
-					        unsigned async_cnt,
-					        pjsip_tpfactory **p_factory);
+						const pjsip_tls_setting *opt,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name,
+						unsigned async_cnt,
+						pjsip_tpfactory **p_factory);
+
+/**
+ * Start the TLS listener, if the listener is not started yet. This is useful
+ * to start the listener manually, if listener was not started when
+ * PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER is set to 0.
+ *
+ * @param factory	The SIP TLS transport factory.
+ *
+ * @param local		The address where the listener should be bound to.
+ *			Both IP interface address and port fields are optional.
+ *			If IP interface address is not specified, socket
+ *			will be bound to PJ_INADDR_ANY. If port is not
+ *			specified, socket will be bound to any port
+ *			selected by the operating system.
+ *
+ * @param a_name	The published address for the listener.
+ *			If this argument is NULL, then the bound address will
+ *			be used as the published address.
+ *
+ * @return		PJ_SUCCESS when the listener has been successfully
+ *			started.
+ */
+PJ_DECL(pj_status_t) pjsip_tls_transport_lis_start(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name);
+
+
+/**
+ * Restart the TLS listener. This will close the listener socket and recreate
+ * the socket based on the config used when starting the transport.
+ *
+ * @param factory	The SIP TLS transport factory.
+ *
+ * @param local		The address where the listener should be bound to.
+ *			Both IP interface address and port fields are optional.
+ *			If IP interface address is not specified, socket
+ *			will be bound to PJ_INADDR_ANY. If port is not
+ *			specified, socket will be bound to any port
+ *			selected by the operating system.
+ *
+ * @param a_name	The published address for the listener.
+ *			If this argument is NULL, then the bound address will
+ *			be used as the published address.
+ *
+ * @return		PJ_SUCCESS when the listener has been successfully
+ *			restarted.
+ *
+ */
+PJ_DECL(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name);
 
 PJ_END_DECL
Index: /pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_transport_udp.h	(revision 5649)
@@ -320,4 +320,49 @@
 						 const pjsip_host_port *a_name);
 
+/**
+ * Restart the transport. Several operations are supported by this function:
+ *  - if transport was made temporarily unavailable to SIP stack with
+ *    pjsip_udp_transport_pause() and PJSIP_UDP_TRANSPORT_KEEP_SOCKET,
+ *    application can make the transport available to the SIP stack
+ *    again, by specifying PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag here.
+ *  - if application wants to replace the internal socket with a new
+ *    socket, it must specify PJSIP_UDP_TRANSPORT_DESTROY_SOCKET when
+ *    calling this function, so that the internal socket will be destroyed
+ *    if it hasn't been closed. In this case, application has two choices
+ *    on how to create the new socket: 1) to let the transport create
+ *    the new socket, in this case the \a sock option should be set
+ *    to \a PJ_INVALID_SOCKET and optionally the \a local parameter can be
+ *    filled with the desired address and port where the new socket 
+ *    should be bound to, or 2) to specify its own socket to be used
+ *    by this transport, by specifying a valid socket in \a sock argument
+ *    and set the \a local argument to NULL. In both cases, application
+ *    may specify the published address of the socket in \a a_name
+ *    argument. This is another version of pjsip_udp_transport_restart() 
+ *    able to restart IPv6 transport.
+ *
+ * @param transport	The UDP transport.
+ * @param option	Restart option.
+ * @param sock		Optional socket to be used by the transport.
+ * @param local		The address where the socket should be bound to.
+ *			If this argument is NULL, socket will be bound
+ *			to any available port.
+ * @param a_name	Optionally specify the published address for
+ *			this transport. If the socket is not replaced
+ *			(PJSIP_UDP_TRANSPORT_KEEP_SOCKET flag is
+ *			specified), then if this argument is NULL, the
+ *			previous value will be used. If the socket is
+ *			replaced and this argument is NULL, the bound
+ *			address will be used as the published address 
+ *			of the transport.
+ *
+ * @return		PJ_SUCCESS if transport can be restarted, or
+ *			the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsip_udp_transport_restart2(pjsip_transport *transport,
+					        unsigned option,
+					        pj_sock_t sock,
+					        const pj_sockaddr *local,
+					        const pjsip_host_port *a_name);
+
 
 PJ_END_DECL
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 5649)
@@ -617,4 +617,86 @@
 
 } pjsua_contact_rewrite_method;
+
+
+/**
+ * This enumeration specifies the operation when handling IP change.
+ */
+typedef enum pjsua_ip_change_op {
+    /**
+     * Hasn't start ip change process.
+     */
+    PJSUA_IP_CHANGE_OP_NULL,
+
+    /**
+     * The restart listener process.
+     */
+    PJSUA_IP_CHANGE_OP_RESTART_LIS,
+
+    /**
+     * The shutdown transport process.
+     */
+    PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP,
+
+    /**
+     * The update contact process.
+     */
+    PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT,
+
+    /**
+     * The hanging up call process.
+     */
+    PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS,
+
+    /**
+     * The re-INVITE call process.
+     */
+    PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+
+} pjsua_ip_change_op;
+
+
+/**
+ * This will contain the information of the callback \a on_ip_change_progress.
+ */
+typedef union pjsua_ip_change_op_info {
+    /**
+     * The information from listener restart operation.
+     */
+    struct {
+	int transport_id;
+    } lis_restart;
+
+    /**
+     * The information from shutdown transport.
+     */
+    struct {
+	int acc_id;
+    } acc_shutdown_tp;
+
+    /**
+     * The information from updating contact.
+     */
+    struct {
+	pjsua_acc_id acc_id;
+	pj_bool_t is_register;	/**< SIP Register if PJ_TRUE.	    */
+	int code;		/**< SIP status code received.	    */
+    } acc_update_contact;
+
+    /**
+     * The information from hanging up call operation.
+     */
+    struct {
+	pjsua_acc_id acc_id;
+	pjsua_call_id call_id;
+    } acc_hangup_calls;
+
+    /**
+     * The information from re-Invite call operation.
+     */
+    struct {
+	pjsua_acc_id acc_id;
+	pjsua_call_id call_id;
+    } acc_reinvite_calls;
+} pjsua_ip_change_op_info;
 
 
@@ -1417,4 +1499,17 @@
     pj_stun_resolve_cb on_stun_resolution_complete;
 
+    /** 
+     * Calling #pjsua_handle_ip_change() may involve different operation. This 
+     * callback is called to report the progress of each enabled operation.
+     *
+     * @param op	The operation.
+     * @param status	The status of operation.
+     * @param info	The info from the operation
+     * 
+     */
+    void (*on_ip_change_progress)(pjsua_ip_change_op op,
+				  pj_status_t status,
+				  const pjsua_ip_change_op_info *info);
+
 } pjsua_callback;
 
@@ -2081,4 +2176,72 @@
     unsigned	     index;
 };
+
+
+/**
+ * This structure describe the parameter passed to #pjsua_handle_ip_change().
+ */
+typedef struct pjsua_ip_change_param
+{
+    /**
+     * If set to PJ_TRUE, this will restart the transport listener.
+     * 
+     * Default : PJ_TRUE
+     */
+    pj_bool_t	    restart_listener;
+
+    /** 
+     * If \a restart listener is set to PJ_TRUE, some delay might be needed 
+     * for the listener to be restarted. Use this to set the delay.
+     * 
+     * Default : PJSUA_TRANSPORT_RESTART_DELAY_TIME
+     */
+    unsigned	    restart_lis_delay;
+
+} pjsua_ip_change_param;
+
+
+/**
+ * This structure describe the account config specific to IP address change.
+ */
+typedef struct pjsua_ip_change_acc_cfg
+{    
+    /**
+     * Shutdown the transport used for account registration. If this is set to
+     * PJ_TRUE, the transport will be shutdown altough it's used by multiple
+     * account. Shutdown transport will be followed by re-Registration if
+     * pjsua_acc_config.allow_contact_rewrite is enabled.
+     *
+     * Default: PJ_TRUE
+     */
+    pj_bool_t		shutdown_tp;
+
+    /**
+     * Hangup active calls associated with the account. If this is set to 
+     * PJ_TRUE, then the calls will be hang up.
+     *
+     * Default: PJ_FALSE
+     */
+    pj_bool_t		hangup_calls;
+
+    /**
+     * Specify the call flags used in the re-INVITE when \a hangup_calls is set 
+     * to PJ_FALSE. If this is set to 0, no re-INVITE will be sent. The 
+     * re-INVITE will be sent after re-Registration is finished.
+     *
+     * Default: PJSUA_CALL_REINIT_MEDIA | PJSUA_CALL_UPDATE_CONTACT |
+     *          PJSUA_CALL_UPDATE_VIA
+     */
+    unsigned		reinvite_flags;
+    
+} pjsua_ip_change_acc_cfg;
+
+
+/**
+ * Call this function to initialize \a pjsua_ip_change_param with default 
+ * values.
+ *
+ * @param param	    The IP change param to be initialized.
+ */
+PJ_DECL(void) pjsua_ip_change_param_default(pjsua_ip_change_param *param);
 
 
@@ -2303,4 +2466,29 @@
 PJ_DECL(void) pjsua_dump(pj_bool_t detail);
 
+
+/**
+ * Inform the stack that IP address change event was detected. 
+ * The stack will:
+ * 1. Restart the listener (this step is configurable via 
+ *    \a pjsua_ip_change_param.restart_listener).
+ * 2. Shutdown the transport used by account registration (this step is 
+ *    configurable via \a pjsua_acc_config.ip_change_cfg.shutdown_tp).
+ * 3. Update contact URI by sending re-Registration (this step is configurable 
+ *    via a\ pjsua_acc_config.allow_contact_rewrite and 
+ *    a\ pjsua_acc_config.contact_rewrite_method)
+ * 4. Hangup active calls (this step is configurable via 
+ *    a\ pjsua_acc_config.ip_change_cfg.hangup_calls) or 
+ *    continue the call by sending re-INVITE 
+ *    (configurable via \a pjsua_acc_config.ip_change_cfg.reinvite_flags).
+ *
+ * @param param		The IP change parameter, have a look at 
+ *			#pjsua_ip_change_param.
+ *
+ * @return		PJ_SUCCESS on success, other on error.
+ */
+PJ_DECL(pj_status_t) pjsua_handle_ip_change(
+					   const pjsua_ip_change_param *param);
+
+
 /**
  * @}
@@ -2577,4 +2765,20 @@
 PJ_DECL(pj_status_t) pjsua_transport_close( pjsua_transport_id id,
 					    pj_bool_t force );
+
+
+/**
+ * Start the listener of the transport. This is useful when listener is not 
+ * automatically started when creating the transport.
+ *
+ * @param id		Transport ID.
+ * @param cfg		The new transport config used by the listener. 
+ *			Only port, public_addr and bound_addr are used at the 
+ *			moment.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pjsua_transport_lis_start( pjsua_transport_id id,
+					    const pjsua_transport_config *cfg);
+
 
 /**
@@ -3542,5 +3746,11 @@
      * Default: PJ_TRUE
      */
-    pj_bool_t         register_on_acc_add;
+    pj_bool_t		register_on_acc_add;
+
+    /**
+     * Specify account configuration specific to IP address change used when
+     * calling #pjsua_handle_ip_change().
+     */
+    pjsua_ip_change_acc_cfg ip_change_cfg;
 
 } pjsua_acc_config;
@@ -5729,4 +5939,13 @@
 
 /**
+ * Specify the delay needed when restarting the transport/listener.
+ * e.g: 10 msec on Linux or Android, and 0 on the other platforms.
+ */
+#ifndef PJSUA_TRANSPORT_RESTART_DELAY_TIME
+#   define PJSUA_TRANSPORT_RESTART_DELAY_TIME	10
+#endif
+
+
+/**
  * This structure describes media configuration, which will be specified
  * when calling #pjsua_init(). Application MUST initialize this structure
Index: /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsua-lib/pjsua_internal.h	(revision 5649)
@@ -286,4 +286,5 @@
     pjsip_transport_type_e tp_type; /**< Transport type (for local acc or
 				         transport binding)		*/
+    pjsua_ip_change_op ip_change_op;/**< IP change process progress.	*/
 } pjsua_acc;
 
@@ -304,4 +305,5 @@
     } data;
 
+    pj_bool_t		     is_restarting;
 } pjsua_transport_data;
 
@@ -868,4 +870,14 @@
 void pjsua_call_schedule_reinvite_check(pjsua_call *call, unsigned delay_ms);
 
+/*
+ * Update contact per account on IP change process.
+ */
+pj_status_t pjsua_acc_update_contact_on_ip_change(pjsua_acc *acc);
+
+/*
+ * Call handling per account on IP change process.
+ */
+pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc);
+
 PJ_END_DECL
 
Index: /pjproject/trunk/pjsip/include/pjsua2/account.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsua2/account.hpp	(revision 5649)
@@ -882,4 +882,54 @@
 
 /**
+ * Account config specific to IP address change.
+ */
+typedef struct AccountIpChangeConfig
+{    
+    /**
+     * Shutdown the transport used for account registration. If this is set to
+     * PJ_TRUE, the transport will be shutdown altough it's used by multiple
+     * account. Shutdown transport will be followed by re-Registration if
+     * AccountConfig.natConfig.contactRewriteUse is enabled.
+     *
+     * Default: true
+     */
+    bool    		shutdownTp;
+
+    /**
+     * Hangup active calls associated with the acount. If this is set to true, 
+     * then the calls will be hang up.
+     *
+     * Default: false
+     */
+    bool		hangupCalls;
+
+    /**
+     * Specify the call flags used in the re-INVITE when \a hangupCalls is set 
+     * to false. If this is set to 0, no re-INVITE will be sent. The 
+     * re-INVITE will be sent after re-Registration is finished.
+     *
+     * Default: PJSUA_CALL_REINIT_MEDIA | PJSUA_CALL_UPDATE_CONTACT |
+     *          PJSUA_CALL_UPDATE_VIA
+     */
+    unsigned		reinviteFlags;
+
+public:
+    /**
+     * Read this object from a container node.
+     *
+     * @param node		Container to read values from.
+     */
+    virtual void readObject(const ContainerNode &node) throw(Error);
+
+    /**
+     * Write this object to a container node.
+     *
+     * @param node		Container to write values to.
+     */
+    virtual void writeObject(ContainerNode &node) const throw(Error);
+    
+} AccountIpChangeConfig;
+
+/**
  * Account configuration.
  */
@@ -941,4 +991,9 @@
      */
     AccountVideoConfig	videoConfig;
+
+    /**
+     * IP Change settings.
+     */
+    AccountIpChangeConfig ipChangeConfig;
 
 public:
Index: /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5648)
+++ /pjproject/trunk/pjsip/include/pjsua2/endpoint.hpp	(revision 5649)
@@ -319,4 +319,101 @@
     int			accountIndex;
 };
+
+/**
+ * Parameter of Endpoint::handleIpChange().
+ */
+struct IpChangeParam {
+    /**
+     * If set to PJ_TRUE, this will restart the transport listener.
+     * 
+     * Default : PJ_TRUE
+     */
+    bool	    restartListener;
+
+    /** 
+     * If \a restartListener is set to PJ_TRUE, some delay might be needed 
+     * for the listener to be restarted. Use this to set the delay.
+     * 
+     * Default : PJSUA_TRANSPORT_RESTART_DELAY_TIME
+     */
+    unsigned	    restartLisDelay;
+public:
+    /**
+     * Constructor.
+     */
+    IpChangeParam();
+
+    /**
+     * Export to pjsua_ip_change_param.
+     */
+    pjsua_ip_change_param toPj() const;
+
+    /**
+     * Convert from pjsip
+     */
+    void fromPj(const pjsua_ip_change_param &param);
+};
+
+/**
+ * Information of Update contact on IP change progress.
+ */
+struct RegProgressParam
+{
+    /**
+     * Indicate if this is a Register or Un-Register message.
+     */
+    bool    isRegister;
+
+    /**
+     * SIP status code received.
+     */
+    int	    code;
+};
+
+/**
+ * Parameter of Endpoint::onIpChangeProgress().
+ */
+struct OnIpChangeProgressParam
+{
+    /**
+     * The IP change progress operation.
+     */
+    pjsua_ip_change_op	op;
+
+    /**
+     * The operation progress status.
+     */
+    pj_status_t		status;
+
+    /**
+     * Information of the transport id. This is only available when the 
+     * operation is PJSUA_IP_CHANGE_OP_RESTART_LIS.
+     */
+    TransportId		transportId;
+
+    /**
+     * Information of the account id. This is only available when the 
+     * operation is:
+     * - PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP 
+     * - PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT 
+     * - PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS
+     * - PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+     */
+    int			accId;
+
+    /**
+     * Information of the call id. This is only available when the operation is
+     * PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS or 
+     * PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS
+     */
+    int			callId;
+
+    /**
+     * Registration information. This is only available when the operation is
+     * PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT
+     */
+    RegProgressParam	regInfo;
+};
+
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1377,4 +1474,29 @@
     void resetVideoCodecParam(const string &codec_id) throw(Error);
 
+    /*************************************************************************
+     * IP Change
+     */
+
+    /**
+     * Inform the stack that IP address change event was detected.
+     * The stack will:
+     * 1. Restart the listener (this step is configurable via
+     *    \a IpChangeParam.restartListener).
+     * 2. Shutdown the transport used by account registration (this step is
+     *    configurable via \a AccountConfig.ipChangeConfig.shutdownTp).
+     * 3. Update contact URI by sending re-Registration (this step is 
+     *    configurable via a\ AccountConfig.natConfig.contactRewriteUse and
+     *    a\ AccountConfig.natConfig.contactRewriteMethod)
+     * 4. Hangup active calls (this step is configurable via
+     *    a\ AccountConfig.ipChangeConfig.hangupCalls) or
+     *    continue the call by sending re-INVITE
+     *    (configurable via \a AccountConfig.ipChangeConfig.reinviteFlags).
+     *
+     * @param param	The IP change parameter, have a look at #IpChangeParam.
+     *
+     * @return		PJ_SUCCESS on success, other on error.
+     */
+    void handleIpChange(const IpChangeParam &param) throw(Error);
+
 public:
     /*
@@ -1438,4 +1560,14 @@
      */
     virtual void onSelectAccount(OnSelectAccountParam &prm)
+    { PJ_UNUSED_ARG(prm); }
+
+    /**
+     * Calling #handleIpChange() may involve different operation. This 
+     * callback is called to report the progress of each enabled operation.
+     *
+     * @param prm	Callback parameters.
+     * 
+     */
+    virtual void onIpChangeProgress(OnIpChangeProgressParam &prm)
     { PJ_UNUSED_ARG(prm); }
 
@@ -1588,4 +1720,9 @@
                                    pjmedia_srtp_setting *srtp_opt);
 
+    static void
+    on_ip_change_progress(pjsua_ip_change_op op,
+			  pj_status_t status,
+			  const pjsua_ip_change_op_info *info);
+
 private:
     void clearCodecInfoList(CodecInfoVector &codec_list);
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 5649)
@@ -62,4 +62,6 @@
     pj_qos_params	     qos_params;
     pj_sockopt_params	     sockopt_params;
+    pj_bool_t		     reuse_addr;        
+    unsigned		     async_cnt;    
 
     /* Group lock to be used by TCP listener and ioqueue key */
@@ -242,4 +244,116 @@
  */
 
+static void update_bound_addr(struct tcp_listener *listener,
+			      const pj_sockaddr *local)
+{
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+    int af = pjsip_transport_type_get_af(listener->factory.type);
+
+    /* Bind address may be different than factory.local_addr because
+     * factory.local_addr will be resolved.
+     */
+    if (local) {
+	pj_sockaddr_cp(&listener->bound_addr, local);
+    }
+    else {
+	pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
+    }
+    pj_sockaddr_cp(listener_addr, &listener->bound_addr);
+}
+
+static pj_status_t update_factory_addr(struct tcp_listener *listener,				       
+				       const pjsip_host_port *addr_name)
+{
+    pj_status_t status = PJ_SUCCESS;    
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;    
+
+    /* If published host/IP is specified, then use that address as the
+     * listener advertised address.
+     */
+    if (addr_name && addr_name->host.slen) {
+	pj_sockaddr tmp;
+	int af = pjsip_transport_type_get_af(listener->factory.type);
+
+	/* Verify that address given in a_name (if any) is valid */
+	status = pj_sockaddr_init(af, &tmp, &addr_name->host,
+				  (pj_uint16_t)addr_name->port);
+	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
+	    (af == pj_AF_INET() && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
+	{
+	    /* Invalid address */
+	    return PJ_EINVAL;
+	}
+
+	/* Copy the address */
+	listener->factory.addr_name = *addr_name;
+	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
+		  &addr_name->host);
+	listener->factory.addr_name.port = addr_name->port;
+
+    } else {
+	/* No published address is given, use the bound address */
+
+	/* If the address returns 0.0.0.0, use the default
+	 * interface address as the transport's address.
+	 */
+	if (!pj_sockaddr_has_addr(listener_addr)) {
+	    pj_sockaddr hostip;
+
+	    status = pj_gethostip(listener->bound_addr.addr.sa_family,
+				  &hostip);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    pj_sockaddr_copy_addr(listener_addr, &hostip);
+	}
+
+	/* Save the address name */
+	sockaddr_to_host_port(listener->factory.pool,
+			      &listener->factory.addr_name,
+			      listener_addr);
+    }
+
+    /* If port is zero, get the bound port */
+    if (listener->factory.addr_name.port == 0) {
+	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
+    }
+
+    pj_ansi_snprintf(listener->factory.obj_name,
+		     sizeof(listener->factory.obj_name),
+		     "tcptp:%d", listener->factory.addr_name.port);
+    return status;
+}
+
+static void update_transport_info(struct tcp_listener *listener)
+{    
+    enum { INFO_LEN = 100 };
+    char local_addr[PJ_INET6_ADDRSTRLEN + 10];
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+    /* Set transport info. */
+    if (listener->factory.info == NULL) {
+	listener->factory.info = (char*)pj_pool_alloc(listener->factory.pool,
+						      INFO_LEN);
+    }
+    pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
+    pj_ansi_snprintf(
+	    listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]",
+	    local_addr,
+	    (int)listener->factory.addr_name.host.slen,
+	    listener->factory.addr_name.host.ptr,
+	    listener->factory.addr_name.port);
+
+    if (listener->asock) {
+	PJ_LOG(4, (listener->factory.obj_name,
+	       "SIP TCP listener ready for incoming connections at %.*s:%d",
+	       (int)listener->factory.addr_name.host.slen,
+	       listener->factory.addr_name.host.ptr,
+	       listener->factory.addr_name.port));
+    } else {
+	PJ_LOG(4, (listener->factory.obj_name, "SIP TCP is ready "
+	       "(client only)"));
+    }
+}
+
 /*
  * This is the public API to create, initialize, register, and start the
@@ -251,34 +365,11 @@
 					pjsip_tpfactory **p_factory
 					)
-{
-    enum { INFO_LEN = 100 };
-    char local_addr[PJ_INET6_ADDRSTRLEN+10];
-    pj_pool_t *pool;
-    pj_sock_t sock = PJ_INVALID_SOCKET;
-    struct tcp_listener *listener;
-    pj_activesock_cfg asock_cfg;
-    pj_activesock_cb listener_cb;
-    pj_sockaddr *listener_addr;
-    int addr_len;
-    pj_bool_t has_listener = PJ_FALSE;
+{        
+    pj_pool_t *pool;    
+    struct tcp_listener *listener;        
     pj_status_t status;
 
     /* Sanity check */
     PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);
-
-    /* Verify that address given in a_name (if any) is valid */
-    if (cfg->addr_name.host.slen) {
-	pj_sockaddr tmp;
-
-	status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, 
-				  (pj_uint16_t)cfg->addr_name.port);
-	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
-	    (cfg->af==pj_AF_INET() && 
-	     tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) 
-	{
-	    /* Invalid address */
-	    return PJ_EINVAL;
-	}
-    }
 
     pool = pjsip_endpt_create_pool(endpt, "tcptp", POOL_LIS_INIT, 
@@ -292,8 +383,10 @@
 						     PJSIP_TRANSPORT_TCP6;
     listener->factory.type_name = (char*)
-		pjsip_transport_get_type_name(listener->factory.type);
+			 pjsip_transport_get_type_name(listener->factory.type);
     listener->factory.flag = 
-	pjsip_transport_get_flag_from_type(listener->factory.type);
+		    pjsip_transport_get_flag_from_type(listener->factory.type);
     listener->qos_type = cfg->qos_type;
+    listener->reuse_addr = cfg->reuse_addr;
+    listener->async_cnt = cfg->async_cnt;
     pj_memcpy(&listener->qos_params, &cfg->qos_params,
 	      sizeof(cfg->qos_params));
@@ -308,147 +401,14 @@
 					    &listener->factory.lock);
     if (status != PJ_SUCCESS)
-	goto on_error;
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    /* Create socket */
-    status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Apply QoS, if specified */
-    status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 
-				2, listener->factory.obj_name, 
-				"SIP TCP listener socket");
-
-    /* Apply SO_REUSEADDR */
-    if (cfg->reuse_addr) {
-	int enabled = 1;
-	status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
-				    &enabled, sizeof(enabled));
-	if (status != PJ_SUCCESS) {
-	    PJ_PERROR(4,(listener->factory.obj_name, status,
-		         "Warning: error applying SO_REUSEADDR"));
-	}
-    }
-
-    /* Apply socket options, if specified */
-    if (cfg->sockopt_params.cnt)
-	status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params);
-
-#else
-    PJ_UNUSED_ARG(addr_len);
-#endif
-
-    /* Bind address may be different than factory.local_addr because
-     * factory.local_addr will be resolved below.
-     */
-    pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);
-
-    /* Bind socket */
-    listener_addr = &listener->factory.local_addr;
-    pj_sockaddr_cp(listener_addr, &cfg->bind_addr);
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    status = pj_sock_bind(sock, listener_addr, 
-			  pj_sockaddr_get_len(listener_addr));
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Retrieve the bound address */
-    addr_len = pj_sockaddr_get_len(listener_addr);
-    status = pj_sock_getsockname(sock, listener_addr, &addr_len);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-#endif
-
-    /* If published host/IP is specified, then use that address as the
-     * listener advertised address.
-     */
-    if (cfg->addr_name.host.slen) {
-	/* Copy the address */
-	listener->factory.addr_name = cfg->addr_name;
-	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
-		  &cfg->addr_name.host);
-	listener->factory.addr_name.port = cfg->addr_name.port;
-
-    } else {
-	/* No published address is given, use the bound address */
-
-	/* If the address returns 0.0.0.0, use the default
-	 * interface address as the transport's address.
-	 */
-	if (!pj_sockaddr_has_addr(listener_addr)) {
-	    pj_sockaddr hostip;
-
-	    status = pj_gethostip(listener->bound_addr.addr.sa_family,
-	                          &hostip);
-	    if (status != PJ_SUCCESS)
-		goto on_error;
-
-	    pj_sockaddr_copy_addr(listener_addr, &hostip);
-	}
-
-	/* Save the address name */
-	sockaddr_to_host_port(listener->factory.pool, 
-			      &listener->factory.addr_name, 
-			      listener_addr);
-    }
-
-    /* If port is zero, get the bound port */
-    if (listener->factory.addr_name.port == 0) {
-	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
-    }
-
-    pj_ansi_snprintf(listener->factory.obj_name, 
-		     sizeof(listener->factory.obj_name),
-		     "tcptp:%d",  listener->factory.addr_name.port);
-
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    /* Start listening to the address */
-    status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-
-    /* Create active socket */
-    pj_activesock_cfg_default(&asock_cfg);
-    if (cfg->async_cnt > MAX_ASYNC_CNT) 
-	asock_cfg.async_cnt = MAX_ASYNC_CNT;
-    else
-	asock_cfg.async_cnt = cfg->async_cnt;
-
-#endif
+	goto on_error;    
 
     /* Create group lock */
     status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
     if (status != PJ_SUCCESS)
-	return status;
+	goto on_error;
 
     pj_grp_lock_add_ref(listener->grp_lock);
     pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
 			    &lis_on_destroy);
-
-    asock_cfg.grp_lock = listener->grp_lock;
-
-    pj_bzero(&listener_cb, sizeof(listener_cb));
-    listener_cb.on_accept_complete = &on_accept_complete;
-
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
-				  pjsip_endpt_get_ioqueue(endpt), 
-				  &listener_cb, listener,
-				  &listener->asock);
-
-#endif
 
     /* Register to transport manager */
@@ -456,5 +416,24 @@
     listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
     listener->factory.create_transport = lis_create_transport;
-    listener->factory.destroy = lis_destroy;
+    listener->factory.destroy = lis_destroy;    
+
+#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
+              PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
+    /* Start listener. */
+    status = pjsip_tcp_transport_lis_start(&listener->factory, &cfg->bind_addr, 
+					   &cfg->addr_name);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+#else
+    update_bound_addr(listener, &cfg->bind_addr);
+    status = update_factory_addr(listener, &cfg->addr_name);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Set transport info. */
+    update_transport_info(listener);
+#endif
+
     listener->is_registered = PJ_TRUE;
     status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
@@ -465,40 +444,4 @@
     }
 
-#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    /* Start pending accept() operations */
-    status = pj_activesock_start_accept(listener->asock, pool);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-	
-    has_listener = PJ_TRUE;
-
-#endif
-
-    /* Set transport info. */
-    if (listener->factory.info == NULL) {
-	listener->factory.info = (char*) pj_pool_alloc(listener->factory.pool,
-						       INFO_LEN);
-    }
-    pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
-    pj_ansi_snprintf( 
-	listener->factory.info, INFO_LEN, "tcp %s [published as %.*s:%d]",
-	local_addr,
-	(int)listener->factory.addr_name.host.slen,
-	listener->factory.addr_name.host.ptr,
-	listener->factory.addr_name.port);
-
-    if (has_listener) {
-        PJ_LOG(4,(listener->factory.obj_name, 
-	         "SIP TCP listener ready for incoming connections at %.*s:%d",
-	         (int)listener->factory.addr_name.host.slen,
-	         listener->factory.addr_name.host.ptr,
-	         listener->factory.addr_name.port));
-    } else {
-	PJ_LOG(4,(listener->factory.obj_name, "SIP TCP is ready "
-		  "(client only)"));    
-    }
-
     /* Return the pointer to user */
     if (p_factory) *p_factory = &listener->factory;
@@ -507,6 +450,4 @@
 
 on_error:
-    if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET)
-	pj_sock_close(sock);
     lis_destroy(&listener->factory);
     return status;
@@ -572,10 +513,7 @@
 }
 
-
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory)
-{
-    struct tcp_listener *listener = (struct tcp_listener *)factory;
-
+/* This will close the listener. */
+static void lis_close(struct tcp_listener *listener)
+{
     if (listener->is_registered) {
 	pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory);
@@ -587,4 +525,12 @@
 	listener->asock = NULL;
     }
+}
+
+/* This callback is called by transport manager to destroy listener */
+static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+{
+    struct tcp_listener *listener = (struct tcp_listener *)factory;
+
+    lis_close(listener);
 
     if (listener->grp_lock) {
@@ -1638,4 +1584,134 @@
 
 
+PJ_DEF(pj_status_t) pjsip_tcp_transport_lis_start(pjsip_tpfactory *factory,
+						 const pj_sockaddr *local,
+					         const pjsip_host_port *a_name)
+{
+    pj_activesock_cfg asock_cfg;
+    pj_activesock_cb listener_cb;
+    pj_sock_t sock = PJ_INVALID_SOCKET;
+    int addr_len, af;    
+    struct tcp_listener *listener = (struct tcp_listener *)factory;
+    pj_sockaddr *listener_addr = &factory->local_addr;
+    pj_status_t status = PJ_SUCCESS;
+
+    /* Nothing to be done, if listener already started. */
+    if (listener->asock)
+	return PJ_SUCCESS;
+    
+    update_bound_addr(listener, local);
+      
+    addr_len = pj_sockaddr_get_len(listener_addr);
+    af = pjsip_transport_type_get_af(listener->factory.type);
+
+    /* Create socket */
+    status = pj_sock_socket(af, pj_SOCK_STREAM(), 0, &sock);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Apply QoS, if specified */
+    status = pj_sock_apply_qos2(sock, listener->qos_type,
+				&listener->qos_params, 2,
+				listener->factory.obj_name,
+				"SIP TCP listener socket");
+
+    /* Apply SO_REUSEADDR */
+    if (listener->reuse_addr) {
+	int enabled = 1;
+	status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
+				    &enabled, sizeof(enabled));
+	if (status != PJ_SUCCESS) {
+	    PJ_LOG(1, ("TRACE", "fail set reuseaddr"));
+	    PJ_PERROR(4, (listener->factory.obj_name, status,
+		"Warning: error applying SO_REUSEADDR"));
+	}
+    }
+
+    /* Apply socket options, if specified */
+    if (listener->sockopt_params.cnt)
+	status = pj_sock_setsockopt_params(sock, &listener->sockopt_params);
+
+    status = pj_sock_bind(sock, listener_addr, addr_len);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Retrieve the bound address */
+    status = pj_sock_getsockname(sock, &listener->factory.local_addr, 
+				 &addr_len);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    status = update_factory_addr(listener, a_name);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Start listening to the address */
+    status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+
+    /* Create active socket */
+    pj_activesock_cfg_default(&asock_cfg);
+    if (listener->async_cnt > MAX_ASYNC_CNT)
+	asock_cfg.async_cnt = MAX_ASYNC_CNT;
+    else
+	asock_cfg.async_cnt = listener->async_cnt;
+
+    asock_cfg.grp_lock = listener->grp_lock;
+    pj_bzero(&listener_cb, sizeof(listener_cb));
+    listener_cb.on_accept_complete = &on_accept_complete;
+
+    status = pj_activesock_create(listener->factory.pool, sock,
+				  pj_SOCK_STREAM(), &asock_cfg,
+				  pjsip_endpt_get_ioqueue(listener->endpt),
+				  &listener_cb, listener,
+				  &listener->asock);
+
+    /* Start pending accept() operations */
+    status = pj_activesock_start_accept(listener->asock,
+					listener->factory.pool);
+
+    update_transport_info(listener);
+
+    return status;
+
+on_error:
+    if (listener->asock == NULL && sock != PJ_INVALID_SOCKET)
+	pj_sock_close(sock);
+
+    return status;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_tcp_transport_restart(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name)
+{
+    pj_status_t status = PJ_SUCCESS;
+    struct tcp_listener *listener = (struct tcp_listener *)factory;
+
+    lis_close(listener);
+
+    status = pjsip_tcp_transport_lis_start(factory, local, a_name);
+    if (status != PJ_SUCCESS) {	
+	tcp_perror(listener->factory.obj_name,
+		   "Unable to start listener after closing it", status);
+
+	return status;
+    }
+    
+    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
+					    &listener->factory);
+    if (status != PJ_SUCCESS) {
+	tcp_perror(listener->factory.obj_name,
+		   "Unable to register the transport listener", status);
+    } else {
+	listener->is_registered = PJ_TRUE;	
+    }    
+
+    return status;
+}
+
 #endif	/* PJ_HAS_TCP */
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 5649)
@@ -58,5 +58,6 @@
     pj_sockaddr		     bound_addr;
     pj_ssl_cert_t	    *cert;
-    pjsip_tls_setting	     tls_setting;
+    pjsip_tls_setting	     tls_setting;    
+    unsigned		     async_cnt;    
 
     /* Group lock to be used by TLS transport and ioqueue key */
@@ -283,14 +284,171 @@
  */
 
+
+static void set_ssock_param(pj_ssl_sock_param *ssock_param,
+    struct tls_listener *listener)
+{
+    int af, sip_ssl_method;
+    pj_uint32_t sip_ssl_proto;
+
+    /* Build SSL socket param */
+    af = pjsip_transport_type_get_af(listener->factory.type);
+    pj_ssl_sock_param_default(ssock_param);
+    ssock_param->sock_af = af;
+    ssock_param->cb.on_accept_complete = &on_accept_complete;
+    ssock_param->async_cnt = listener->async_cnt;
+    ssock_param->ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
+    ssock_param->timer_heap = pjsip_endpt_get_timer_heap(listener->endpt);
+    ssock_param->require_client_cert = listener->tls_setting.require_client_cert;
+    ssock_param->timeout = listener->tls_setting.timeout;
+    ssock_param->user_data = listener;
+    ssock_param->verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
+					  * due to verification error */
+    if (ssock_param->send_buffer_size < PJSIP_MAX_PKT_LEN)
+	ssock_param->send_buffer_size = PJSIP_MAX_PKT_LEN;
+    if (ssock_param->read_buffer_size < PJSIP_MAX_PKT_LEN)
+	ssock_param->read_buffer_size = PJSIP_MAX_PKT_LEN;
+    ssock_param->ciphers_num = listener->tls_setting.ciphers_num;
+    ssock_param->ciphers = listener->tls_setting.ciphers;
+    ssock_param->curves_num = listener->tls_setting.curves_num;
+    ssock_param->curves = listener->tls_setting.curves;
+    ssock_param->sigalgs = listener->tls_setting.sigalgs;
+    ssock_param->entropy_type = listener->tls_setting.entropy_type;
+    ssock_param->entropy_path = listener->tls_setting.entropy_path;
+    ssock_param->reuse_addr = listener->tls_setting.reuse_addr;
+    ssock_param->qos_type = listener->tls_setting.qos_type;
+    ssock_param->qos_ignore_error = listener->tls_setting.qos_ignore_error;
+    pj_memcpy(&ssock_param->qos_params, &listener->tls_setting.qos_params,
+	      sizeof(ssock_param->qos_params));
+
+    ssock_param->sockopt_ignore_error =
+				    listener->tls_setting.sockopt_ignore_error;
+    /* Copy the sockopt */
+    pj_memcpy(&ssock_param->sockopt_params,
+	      &listener->tls_setting.sockopt_params,
+	      sizeof(listener->tls_setting.sockopt_params));
+
+    sip_ssl_method = listener->tls_setting.method;
+    sip_ssl_proto = listener->tls_setting.proto;
+    ssock_param->proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto);
+}
+
+static void update_bound_addr(struct tls_listener *listener,
+			      const pj_sockaddr *local)
+{
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+    int af = pjsip_transport_type_get_af(listener->factory.type);
+
+    /* Bind address may be different than factory.local_addr because
+     * factory.local_addr will be resolved.
+     */
+    if (local) {
+	pj_sockaddr_cp(&listener->bound_addr, local);
+    } else {
+	pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
+    }
+    pj_sockaddr_cp(listener_addr, &listener->bound_addr);    
+}
+
+static pj_status_t update_factory_addr(struct tls_listener *listener,
+				       const pjsip_host_port *addr_name)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+    if (addr_name && addr_name->host.slen) {
+	pj_sockaddr tmp;
+	int af = pjsip_transport_type_get_af(listener->factory.type);
+
+	status = pj_sockaddr_init(af, &tmp, &addr_name->host,
+				  (pj_uint16_t)addr_name->port);
+	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
+	    (af == pj_AF_INET() && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
+	{
+	    /* Invalid address */
+	    return PJ_EINVAL;
+	}
+
+	/* Copy the address */
+	listener->factory.addr_name = *addr_name;
+	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host,
+		  &addr_name->host);
+	listener->factory.addr_name.port = addr_name->port;
+
+    }
+    else {
+	/* No published address is given, use the bound address */
+
+	/* If the address returns 0.0.0.0, use the default
+	* interface address as the transport's address.
+	*/
+	if (!pj_sockaddr_has_addr(listener_addr)) {
+	    pj_sockaddr hostip;
+
+	    status = pj_gethostip(listener->bound_addr.addr.sa_family,
+				  &hostip);
+	    if (status != PJ_SUCCESS)
+		return status;
+
+	    pj_sockaddr_copy_addr(listener_addr, &hostip);
+	}
+
+	/* Save the address name */
+	sockaddr_to_host_port(listener->factory.pool,
+			      &listener->factory.addr_name, listener_addr);
+    }
+
+    /* If port is zero, get the bound port */
+    if (listener->factory.addr_name.port == 0) {
+	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
+    }
+
+    pj_ansi_snprintf(listener->factory.obj_name,
+		     sizeof(listener->factory.obj_name),
+		     "tlstp:%d", listener->factory.addr_name.port);
+    return status;
+}
+
+static void update_transport_info(struct tls_listener *listener)
+{
+    enum { INFO_LEN = 100 };
+    char local_addr[PJ_INET6_ADDRSTRLEN + 10];
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+    if (listener->factory.info == NULL) {
+	listener->factory.info = (char*)pj_pool_alloc(listener->factory.pool,
+						      INFO_LEN);
+    }
+    pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
+    pj_ansi_snprintf(
+	    listener->factory.info, INFO_LEN, "tls %s [published as %.*s:%d]",
+	    local_addr,
+	    (int)listener->factory.addr_name.host.slen,
+	    listener->factory.addr_name.host.ptr,
+	    listener->factory.addr_name.port);
+
+    if (listener->ssock) {
+	PJ_LOG(4, (listener->factory.obj_name,
+	       "SIP TLS listener is ready for incoming connections "
+	       "at %.*s:%d",
+	       (int)listener->factory.addr_name.host.slen,
+	       listener->factory.addr_name.host.ptr,
+	       listener->factory.addr_name.port));
+    } else {
+	PJ_LOG(4, (listener->factory.obj_name, "SIP TLS is ready "
+	       "(client only)"));
+    }
+}
+
+
 /*
  * This is the public API to create, initialize, register, and start the
  * TLS listener.
  */
-PJ_DEF(pj_status_t) pjsip_tls_transport_start (pjsip_endpoint *endpt,
-					       const pjsip_tls_setting *opt,
-					       const pj_sockaddr_in *local_in,
-					       const pjsip_host_port *a_name,
-					       unsigned async_cnt,
-					       pjsip_tpfactory **p_factory)
+PJ_DEF(pj_status_t) pjsip_tls_transport_start(pjsip_endpoint *endpt,
+    const pjsip_tls_setting *opt,
+    const pj_sockaddr_in *local_in,
+    const pjsip_host_port *a_name,
+    unsigned async_cnt,
+    pjsip_tpfactory **p_factory)
 {
     pj_sockaddr local;
@@ -299,7 +457,68 @@
 	pj_sockaddr_cp(&local, local_in);
 
-    return pjsip_tls_transport_start2(endpt, opt, (local_in? &local : NULL),
-                                      a_name, async_cnt, p_factory);
-}
+    return pjsip_tls_transport_start2(endpt, opt, (local_in ? &local : NULL),
+				      a_name, async_cnt, p_factory);
+}
+
+
+PJ_DEF(pj_status_t) pjsip_tls_transport_lis_start(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pj_ssl_sock_param ssock_param, newsock_param;
+    struct tls_listener *listener = (struct tls_listener *)factory;
+    pj_sockaddr *listener_addr = &listener->factory.local_addr;
+
+    if (listener->ssock)
+	return PJ_SUCCESS;
+
+    set_ssock_param(&ssock_param, listener);
+    update_bound_addr(listener, local);
+    ssock_param.grp_lock = listener->grp_lock;
+
+    /* Create SSL socket */
+    status = pj_ssl_sock_create(listener->factory.pool, &ssock_param, 
+				&listener->ssock);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    if (listener->cert) {
+	status = pj_ssl_sock_set_certificate(listener->ssock, 
+				       listener->factory.pool, listener->cert);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+
+    /* Start accepting incoming connections. Note that some TLS/SSL
+     * backends may not support for SSL socket server.
+     */    
+    pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param));
+    newsock_param.async_cnt = 1;
+    newsock_param.cb.on_data_read = &on_data_read;
+    newsock_param.cb.on_data_sent = &on_data_sent;
+    status = pj_ssl_sock_start_accept2(listener->ssock, listener->factory.pool,
+			    (pj_sockaddr_t*)listener_addr,
+			    pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr),
+			    &newsock_param);
+
+    if (status == PJ_SUCCESS || status == PJ_EPENDING) {
+	pj_ssl_sock_info info;	
+
+	/* Retrieve the bound address */
+	status = pj_ssl_sock_get_info(listener->ssock, &info);
+	if (status == PJ_SUCCESS)
+	    pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr);
+
+    }
+    status = update_factory_addr(listener, a_name);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    update_transport_info(listener);
+
+    return status;    
+}
+
 
 PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
@@ -309,15 +528,8 @@
 					        unsigned async_cnt,
 					        pjsip_tpfactory **p_factory)
-{
-    enum { INFO_LEN = 100 };
-    char local_addr[PJ_INET6_ADDRSTRLEN+10];
+{        
     pj_pool_t *pool;
-    pj_bool_t is_ipv6;
-    int af, sip_ssl_method;
-    pj_uint32_t sip_ssl_proto;
-    struct tls_listener *listener;
-    pj_ssl_sock_param ssock_param, newsock_param;
-    pj_sockaddr *listener_addr;
-    pj_bool_t has_listener;
+    pj_bool_t is_ipv6;    
+    struct tls_listener *listener;    
     pj_status_t status;
 
@@ -325,20 +537,5 @@
     PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
 
-    is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());
-    af = is_ipv6 ? pj_AF_INET6() : pj_AF_INET();
-
-    /* Verify that address given in a_name (if any) is valid */
-    if (a_name && a_name->host.slen) {
-	pj_sockaddr tmp;
-
-	status = pj_sockaddr_init(af, &tmp, &a_name->host,
-				  (pj_uint16_t)a_name->port);
-	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
-	    (!is_ipv6 && tmp.ipv4.sin_addr.s_addr == PJ_INADDR_NONE))
-	{
-	    /* Invalid address */
-	    return PJ_EINVAL;
-	}
-    }
+    is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());    
 
     pool = pjsip_endpt_create_pool(endpt, "tlstp", POOL_LIS_INIT, 
@@ -355,5 +552,6 @@
 		pjsip_transport_get_type_name(listener->factory.type);
     listener->factory.flag = 
-	pjsip_transport_get_flag_from_type(listener->factory.type);
+		pjsip_transport_get_flag_from_type(listener->factory.type);
+    listener->endpt = endpt;
 
     pj_ansi_strcpy(listener->factory.obj_name, "tlstp");
@@ -374,50 +572,10 @@
 	async_cnt = MAX_ASYNC_CNT;
 
-    /* Build SSL socket param */
-    pj_ssl_sock_param_default(&ssock_param);
-    ssock_param.sock_af = af;
-    ssock_param.cb.on_accept_complete = &on_accept_complete;
-    ssock_param.async_cnt = async_cnt;
-    ssock_param.ioqueue = pjsip_endpt_get_ioqueue(endpt);
-    ssock_param.timer_heap = pjsip_endpt_get_timer_heap(endpt);    
-    ssock_param.require_client_cert = listener->tls_setting.require_client_cert;
-    ssock_param.timeout = listener->tls_setting.timeout;
-    ssock_param.user_data = listener;
-    ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
-					 * due to verification error */
-    if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
-	ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
-    if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
-	ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
-    ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
-    ssock_param.ciphers = listener->tls_setting.ciphers;
-    ssock_param.curves_num = listener->tls_setting.curves_num;
-    ssock_param.curves = listener->tls_setting.curves;
-    ssock_param.sigalgs = listener->tls_setting.sigalgs;
-    ssock_param.entropy_type = listener->tls_setting.entropy_type;
-    ssock_param.entropy_path = listener->tls_setting.entropy_path;
-    ssock_param.reuse_addr = listener->tls_setting.reuse_addr;
-    ssock_param.qos_type = listener->tls_setting.qos_type;
-    ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
-    pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
-	      sizeof(ssock_param.qos_params));
-
-    ssock_param.sockopt_ignore_error = 
-				     listener->tls_setting.sockopt_ignore_error;
-    /* Copy the sockopt */
-    pj_memcpy(&ssock_param.sockopt_params, 
-	      &listener->tls_setting.sockopt_params,
-	      sizeof(listener->tls_setting.sockopt_params));
-
-    has_listener = PJ_FALSE;
-
-    sip_ssl_method = listener->tls_setting.method;
-    sip_ssl_proto = listener->tls_setting.proto;
-    ssock_param.proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto); 
+    listener->async_cnt = async_cnt;    
 
     /* Create group lock */
     status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
     if (status != PJ_SUCCESS)
-	return status;
+	goto on_error;
 
     /* Setup group lock handler */
@@ -425,29 +583,4 @@
     pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
 			    &lis_on_destroy);
-
-#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-    ssock_param.grp_lock = listener->grp_lock;
-
-    /* Create SSL socket */
-    status = pj_ssl_sock_create(pool, &ssock_param, &listener->ssock);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-#endif
-
-    /* Bind address may be different than factory.local_addr because
-     * factory.local_addr will be resolved below.
-     */
-    listener_addr = &listener->factory.local_addr;
-    if (local) {
-	pj_sockaddr_cp((pj_sockaddr_t*)listener_addr, 
-		       (const pj_sockaddr_t*)local);
-	pj_sockaddr_cp(&listener->bound_addr, local);
-    } else {
-	pj_sockaddr_init(af, listener_addr, NULL, 0);
-	pj_sockaddr_init(af, &listener->bound_addr, NULL, 0);
-    }
 
     /* Check if certificate/CA list for SSL socket is set */
@@ -465,82 +598,5 @@
 	if (status != PJ_SUCCESS)
 	    goto on_error;
-     }
-
-#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
-      PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
-
-     if (listener->cert) {
-	status = pj_ssl_sock_set_certificate(listener->ssock, pool, 
-					     listener->cert);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-    }
-
-    /* Start accepting incoming connections. Note that some TLS/SSL backends
-     * may not support for SSL socket server.
-     */
-    has_listener = PJ_FALSE;
-
-    pj_memcpy(&newsock_param, &ssock_param, sizeof(newsock_param));
-    newsock_param.async_cnt = 1;
-    newsock_param.cb.on_data_read = &on_data_read;
-    newsock_param.cb.on_data_sent = &on_data_sent;
-    status = pj_ssl_sock_start_accept2(listener->ssock, pool, 
-			  (pj_sockaddr_t*)listener_addr, 
-			  pj_sockaddr_get_len((pj_sockaddr_t*)listener_addr),
-			  &newsock_param);
-    if (status == PJ_SUCCESS || status == PJ_EPENDING) {
-	pj_ssl_sock_info info;
-	has_listener = PJ_TRUE;
-
-	/* Retrieve the bound address */
-	status = pj_ssl_sock_get_info(listener->ssock, &info);
-	if (status == PJ_SUCCESS)
-	    pj_sockaddr_cp(listener_addr, (pj_sockaddr_t*)&info.local_addr);
-    } else if (status != PJ_ENOTSUP) {
-	goto on_error;
-    }
-
-#endif
-
-    /* If published host/IP is specified, then use that address as the
-     * listener advertised address.
-     */
-    if (a_name && a_name->host.slen) {
-	/* Copy the address */
-	listener->factory.addr_name = *a_name;
-	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
-		  &a_name->host);
-	listener->factory.addr_name.port = a_name->port;
-
-    } else {
-	/* No published address is given, use the bound address */
-
-	/* If the address returns 0.0.0.0, use the default
-	 * interface address as the transport's address.
-	 */
-	if (!pj_sockaddr_has_addr(listener_addr)) {
-	    pj_sockaddr hostip;
-
-	    status = pj_gethostip(af, &hostip);
-	    if (status != PJ_SUCCESS)
-		goto on_error;
-
-	    pj_sockaddr_copy_addr(listener_addr, &hostip);
-	}
-
-	/* Save the address name */
-	sockaddr_to_host_port(listener->factory.pool, 
-			      &listener->factory.addr_name, listener_addr);
-    }
-
-    /* If port is zero, get the bound port */
-    if (listener->factory.addr_name.port == 0) {
-	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
-    }
-
-    pj_ansi_snprintf(listener->factory.obj_name, 
-		     sizeof(listener->factory.obj_name),
-		     "tlstp:%d",  listener->factory.addr_name.port);
+    }
 
     /* Register to transport manager */
@@ -549,4 +605,24 @@
     listener->factory.create_transport2 = lis_create_transport;
     listener->factory.destroy = lis_destroy;
+
+#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
+    PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
+    /* Start listener. */
+    status = pjsip_tls_transport_lis_start(&listener->factory, local, a_name);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+#else
+    update_bound_addr(listener, local);
+    /* If published host/IP is specified, then use that address as the
+     * listener advertised address.
+     */
+    status = update_factory_addr(listener, a_name);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Set transport info. */
+    update_transport_info(listener);
+#endif
+
     listener->is_registered = PJ_TRUE;
     status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
@@ -557,29 +633,4 @@
     }
 
-    /* Set transport info. */
-    if (listener->factory.info == NULL) {
-	listener->factory.info = (char*) pj_pool_alloc(listener->factory.pool,
-						       INFO_LEN);
-    }
-    pj_sockaddr_print(listener_addr, local_addr, sizeof(local_addr), 3);
-    pj_ansi_snprintf( 
-	listener->factory.info, INFO_LEN, "tls %s [published as %.*s:%d]",
-	local_addr,
-	(int)listener->factory.addr_name.host.slen,
-	listener->factory.addr_name.host.ptr,
-	listener->factory.addr_name.port);
-
-    if (has_listener) {
-	PJ_LOG(4,(listener->factory.obj_name, 
-		 "SIP TLS listener is ready for incoming connections "
-		 "at %.*s:%d",
-		 (int)listener->factory.addr_name.host.slen,
-		 listener->factory.addr_name.host.ptr,
-		 listener->factory.addr_name.port));
-    } else {
-	PJ_LOG(4,(listener->factory.obj_name, "SIP TLS is ready "
-		  "(client only)"));
-    }
-
     /* Return the pointer to user */
     if (p_factory) *p_factory = &listener->factory;
@@ -610,9 +661,6 @@
 
 
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory)
-{
-    struct tls_listener *listener = (struct tls_listener *)factory;
-
+static void lis_close(struct tls_listener *listener)
+{
     if (listener->is_registered) {
 	pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory);
@@ -624,4 +672,13 @@
 	listener->ssock = NULL;
     }
+}
+
+
+/* This callback is called by transport manager to destroy listener */
+static pj_status_t lis_destroy(pjsip_tpfactory *factory)
+{
+    struct tls_listener *listener = (struct tls_listener *)factory;
+
+    lis_close(listener);
 
     if (listener->grp_lock) {
@@ -635,4 +692,36 @@
 
     return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pjsip_tls_transport_restart(pjsip_tpfactory *factory,
+						const pj_sockaddr *local,
+						const pjsip_host_port *a_name)
+{
+    pj_status_t status = PJ_SUCCESS;
+    struct tls_listener *listener = (struct tls_listener *)factory;
+
+    lis_close(listener);
+
+    status = pjsip_tls_transport_lis_start(factory, local, a_name);
+    if (status != PJ_SUCCESS) {	
+	tls_perror(listener->factory.obj_name, 
+		   "Unable to start listener after closing it", status);
+
+	return status;
+    }
+    
+    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
+					    &listener->factory);
+    if (status != PJ_SUCCESS) {
+	tls_perror(listener->factory.obj_name,
+		    "Unable to register the transport listener", status);
+
+	listener->is_registered = PJ_FALSE;	
+    } else {
+	listener->is_registered = PJ_TRUE;	
+    }    
+
+    return status;
 }
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5649)
@@ -1081,8 +1081,19 @@
  */
 PJ_DEF(pj_status_t) pjsip_udp_transport_restart(pjsip_transport *transport,
-					        unsigned option,
+						unsigned option,
 						pj_sock_t sock,
 						const pj_sockaddr_in *local,
 						const pjsip_host_port *a_name)
+{
+    return pjsip_udp_transport_restart2(transport, option, sock, 
+					(pj_sockaddr*)local, a_name);
+}
+
+
+PJ_DEF(pj_status_t) pjsip_udp_transport_restart2(pjsip_transport *transport,
+					         unsigned option,
+					         pj_sock_t sock,
+					         const pj_sockaddr *local,
+					         const pjsip_host_port *a_name)
 {
     struct udp_transport *tp;
@@ -1099,5 +1110,5 @@
      */
     tp->is_paused = PJ_TRUE;
-
+    
     if (option & PJSIP_UDP_TRANSPORT_DESTROY_SOCKET) {
 	char addr_buf[PJ_INET6_ADDRSTRLEN];
@@ -1122,6 +1133,6 @@
 	/* Create the socket if it's not specified */
 	if (sock == PJ_INVALID_SOCKET) {
-	    status = create_socket(pj_AF_INET(), local, 
-				   sizeof(pj_sockaddr_in), &sock);
+	    status = create_socket(local->addr.sa_family, local, 
+				   pj_sockaddr_get_len(local), &sock);
 	    if (status != PJ_SUCCESS)
 		return status;
@@ -1190,3 +1201,2 @@
     return PJ_SUCCESS;
 }
-
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 5649)
@@ -402,4 +402,6 @@
 	acc->tp_type = pjsua_var.tpdata[acc_cfg->transport_id].type;
 
+    acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+
     return PJ_SUCCESS;
 }
@@ -688,4 +690,5 @@
     acc->via_tp = NULL;
     acc->next_rtp_port = 0;
+    acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;    
 
     /* Remove from array */
@@ -1417,4 +1420,9 @@
 	}
     }
+
+    /* IP Change config */
+    acc->cfg.ip_change_cfg.shutdown_tp = cfg->ip_change_cfg.shutdown_tp;
+    acc->cfg.ip_change_cfg.hangup_calls = cfg->ip_change_cfg.hangup_calls;    
+    acc->cfg.ip_change_cfg.reinvite_flags = cfg->ip_change_cfg.reinvite_flags;
 
 on_return:
@@ -2200,4 +2208,13 @@
 
 /*
+ * Timer callback to handle call on IP change process.
+ */
+static void handle_call_on_ip_change_cb(void *user_data)
+{
+    pjsua_acc *acc = (pjsua_acc*)user_data;
+    pjsua_acc_handle_call_on_ip_change(acc);
+}
+
+/*
  * This callback is called by pjsip_regc when outgoing register
  * request has completed.
@@ -2266,5 +2283,6 @@
 	    PJ_LOG(3,(THIS_FILE, "%s: unregistration success",
 		      pjsua_var.acc[acc->index].cfg.id.ptr));
-	} else {
+
+	} else {	    
 	    /* Check and update SIP outbound status first, since the result
 	     * will determine if we should update re-registration
@@ -2306,6 +2324,6 @@
 	    if (acc->cfg.mwi_enabled)
 		pjsua_start_mwi(acc->index, PJ_FALSE);
-	}
-
+
+	}
     } else {
 	PJ_LOG(4, (THIS_FILE, "SIP registration updated status=%d", param->code));
@@ -2349,4 +2367,49 @@
 	reg_info.renew = !param->is_unreg;
 	(*pjsua_var.ua_cfg.cb.on_reg_state2)(acc->index, &reg_info);
+    }
+
+    if (acc->ip_change_op == PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT) {
+	if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+	    pjsua_ip_change_op_info ip_chg_info;
+	    pjsip_regc_info rinfo;
+
+	    pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
+	    pjsip_regc_get_info(param->regc, &rinfo);	    
+	    ip_chg_info.acc_update_contact.acc_id = acc->index;
+	    ip_chg_info.acc_update_contact.code = param->code;
+	    ip_chg_info.acc_update_contact.is_register = !param->is_unreg;
+	    (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(acc->ip_change_op, 
+							 param->status, 
+							 &ip_chg_info);
+	}
+
+	if (PJSIP_IS_STATUS_IN_CLASS(param->code, 200)) {
+	    if (param->expiration < 1) {
+		pj_status_t status;
+		/* Send re-register. */
+		PJ_LOG(3, (THIS_FILE, "%.*s: send registration triggered by IP"
+			   " change", pjsua_var.acc[acc->index].cfg.id.slen,
+			   pjsua_var.acc[acc->index].cfg.id.ptr));
+
+		status = pjsua_acc_set_registration(acc->index, PJ_TRUE);
+		if ((status != PJ_SUCCESS) && 
+		    pjsua_var.ua_cfg.cb.on_ip_change_progress) 
+		{
+		    pjsua_ip_change_op_info ip_chg_info;
+
+		    pj_bzero(&ip_chg_info, sizeof(ip_chg_info));
+		    ip_chg_info.acc_update_contact.acc_id = acc->index;
+		    ip_chg_info.acc_update_contact.is_register = PJ_TRUE;
+		    (*pjsua_var.ua_cfg.cb.on_ip_change_progress)(
+							    acc->ip_change_op, 
+							    status, 
+							    &ip_chg_info);
+		}
+	    } else {
+                /* Avoid deadlock issue when sending BYE or Re-INVITE.  */
+		pjsua_schedule_timer2(&handle_call_on_ip_change_cb, 
+				      (void*)acc, 0);
+	    }
+	} 
     }
     
@@ -2676,5 +2739,5 @@
 	//pjsip_regc_get_info(pjsua_var.acc[acc_id].regc, &reg_info);
 	//pjsua_var.acc[acc_id].auto_rereg.reg_tp = reg_info.transport;
-        
+
         if (pjsua_var.ua_cfg.cb.on_reg_started) {
             (*pjsua_var.ua_cfg.cb.on_reg_started)(acc_id, renew);
@@ -3770,6 +3833,14 @@
 	    pjsip_regc_release_transport(pjsua_var.acc[i].regc);
 
-	    /* Schedule reregistration for this account */
-	    if (acc->cfg.reg_retry_interval) {
+	    if (pjsua_var.acc[i].ip_change_op == 
+					    PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP)
+	    {
+		if (acc->cfg.allow_contact_rewrite) {
+		    pjsua_acc_update_contact_on_ip_change(acc);
+		} else {
+		    pjsua_acc_handle_call_on_ip_change(acc);
+		}
+	    } else if (acc->cfg.reg_retry_interval) {
+		/* Schedule reregistration for this account */
 	        schedule_reregistration(acc);
 	    }
@@ -3780,2 +3851,114 @@
     pj_log_pop_indent();
 }
+
+
+/*
+ * Internal function to update contact on ip change process.
+ */
+pj_status_t pjsua_acc_update_contact_on_ip_change(pjsua_acc *acc)
+{
+    pj_status_t status;
+    pj_bool_t need_unreg = ((acc->cfg.contact_rewrite_method &
+			     PJSUA_CONTACT_REWRITE_UNREGISTER) != 0);
+
+    acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT;
+
+    PJ_LOG(3, (THIS_FILE, "%.*s: send %sregistration triggered "
+	       "by IP change", acc->cfg.id.slen,
+	       acc->cfg.id.ptr, (need_unreg ? "un-" : "")));
+
+    status = pjsua_acc_set_registration(acc->index, !need_unreg);
+
+    if ((status != PJ_SUCCESS) && (pjsua_var.ua_cfg.cb.on_ip_change_progress)) 
+    {
+	pjsua_ip_change_op_info info;
+	
+	pj_bzero(&info, sizeof(info));
+	info.acc_update_contact.acc_id = acc->index;
+	info.acc_update_contact.is_register = !need_unreg;	
+
+	pjsua_var.ua_cfg.cb.on_ip_change_progress(acc->ip_change_op,
+						  status,
+						  &info);
+    }
+    return status;
+}
+
+
+/*
+ * Internal function to handle call on ip change process.
+ */
+pj_status_t pjsua_acc_handle_call_on_ip_change(pjsua_acc *acc)
+{
+    pj_status_t status = PJ_SUCCESS;
+    unsigned i = 0;
+
+    if (acc->cfg.ip_change_cfg.hangup_calls || 
+	acc->cfg.ip_change_cfg.reinvite_flags)
+    {
+	for (i = 0; i < (int)pjsua_var.ua_cfg.max_calls; ++i) {
+	    pjsua_call_info call_info;
+	    pjsua_call_get_info(i, &call_info);
+
+	    if (pjsua_var.calls[i].acc_id != acc->index)
+	    {
+		continue;
+	    }
+
+	    if (acc->cfg.ip_change_cfg.hangup_calls) {
+		acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS;
+		PJ_LOG(3, (THIS_FILE, "call to %.*s: hangup "
+			   "triggered by IP change",
+			   call_info.remote_info.slen,
+			   call_info.remote_info.ptr));
+
+		status = pjsua_call_hangup(i, PJSIP_SC_GONE, NULL, NULL);
+
+		if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+		    pjsua_ip_change_op_info info;
+
+		    pj_bzero(&info, sizeof(info));
+		    info.acc_hangup_calls.acc_id = acc->index;
+		    info.acc_hangup_calls.call_id = call_info.id;
+
+		    pjsua_var.ua_cfg.cb.on_ip_change_progress(
+							     acc->ip_change_op,
+							     status,
+							     &info);
+		}
+	    } else if ((acc->cfg.ip_change_cfg.reinvite_flags) &&
+		(call_info.state == PJSIP_INV_STATE_CONFIRMED))
+	    {
+		acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS;
+
+		call_info.setting.flag |=
+					 acc->cfg.ip_change_cfg.reinvite_flags;
+
+		PJ_LOG(3, (THIS_FILE, "call to %.*s: send "
+			   "re-INVITE with flags 0x%x triggered "
+			   "by IP change",
+			   call_info.remote_info.slen,
+			   call_info.remote_info.ptr,
+			   acc->cfg.ip_change_cfg.reinvite_flags));
+
+		status = pjsua_call_reinvite(i, call_info.setting.flag, NULL);
+
+		if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+		    pjsua_ip_change_op_info info;
+
+		    pj_bzero(&info, sizeof(info));
+		    info.acc_reinvite_calls.acc_id = acc->index;
+		    info.acc_reinvite_calls.call_id = call_info.id;
+
+		    pjsua_var.ua_cfg.cb.on_ip_change_progress(
+							     acc->ip_change_op,
+							     status,
+							     &info);
+		}
+
+	    }
+	}
+    }    
+    acc->ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+    return status;
+}
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 5649)
@@ -306,4 +306,9 @@
 
     cfg->media_stun_use = PJSUA_STUN_RETRY_ON_FAILURE;
+    cfg->ip_change_cfg.shutdown_tp = PJ_TRUE;
+    cfg->ip_change_cfg.hangup_calls = PJ_FALSE;
+    cfg->ip_change_cfg.reinvite_flags = PJSUA_CALL_REINIT_MEDIA |
+					PJSUA_CALL_UPDATE_CONTACT |
+					PJSUA_CALL_UPDATE_VIA;
 }
 
@@ -2368,5 +2373,5 @@
 	pj_memcpy(&tcp_cfg.sockopt_params, &cfg->sockopt_params,
 		  sizeof(tcp_cfg.sockopt_params));
-	
+
 	/* Create the TCP transport */
 	status = pjsip_tcp_transport_start3(pjsua_var.endpt, &tcp_cfg, &tcp);
@@ -2426,6 +2431,5 @@
 	    a_name.host = cfg->public_addr;
 
-	status = pjsip_tls_transport_start2(pjsua_var.endpt,
-					    &cfg->tls_setting,
+	status = pjsip_tls_transport_start2(pjsua_var.endpt, &cfg->tls_setting,
 					    &local_addr, &a_name, 1, &tls);
 	if (status != PJ_SUCCESS) {
@@ -2712,4 +2716,64 @@
 
 
+PJ_DEF(pj_status_t) pjsua_transport_lis_start(pjsua_transport_id id,
+					     const pjsua_transport_config *cfg)
+{
+    pj_status_t status = PJ_SUCCESS;
+    pjsip_transport_type_e tp_type;
+
+    /* Make sure id is in range. */
+    PJ_ASSERT_RETURN(id>=0 && id<(int)PJ_ARRAY_SIZE(pjsua_var.tpdata), 
+		     PJ_EINVAL);
+
+    /* Make sure that transport exists */
+    PJ_ASSERT_RETURN(pjsua_var.tpdata[id].data.ptr != NULL, PJ_EINVAL);
+
+    tp_type = pjsua_var.tpdata[id].type & ~PJSIP_TRANSPORT_IPV6;
+ 
+    if ((tp_type == PJSIP_TRANSPORT_TLS) || (tp_type == PJSIP_TRANSPORT_TCP)) {
+	pj_sockaddr bind_addr;
+	pjsip_host_port addr_name;
+	pjsip_tpfactory *factory = pjsua_var.tpdata[id].data.factory;
+	
+        int af = pjsip_transport_type_get_af(factory->type);
+
+	if (cfg->port)
+	    pj_sockaddr_set_port(&bind_addr, (pj_uint16_t)cfg->port);
+
+	if (cfg->bound_addr.slen) {
+	    status = pj_sockaddr_set_str_addr(af, 
+					      &bind_addr,
+					      &cfg->bound_addr);
+	    if (status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, 
+			     "Unable to resolve transport bound address", 
+			     status);
+		return status;
+	    }
+	}
+
+	/* Set published name */
+	if (cfg->public_addr.slen)
+	    addr_name.host = cfg->public_addr;
+
+	if (tp_type == PJSIP_TRANSPORT_TCP) {
+	    status = pjsip_tcp_transport_lis_start(factory, &bind_addr,
+						   &addr_name);
+	}
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+	else {
+	    status = pjsip_tls_transport_lis_start(factory, &bind_addr,
+						   &addr_name);	
+	}
+#endif	
+    } else if (tp_type == PJSIP_TRANSPORT_UDP) {
+	status = PJ_SUCCESS;
+    } else {
+	status = PJ_EINVAL;
+    }
+    return status;
+}
+
+
 /*
  * Add additional headers etc in msg_data specified by application
@@ -2863,4 +2927,12 @@
 	sel->u.listener = tpdata->data.factory;
     }
+}
+
+
+PJ_DEF(void) pjsua_ip_change_param_default(pjsua_ip_change_param *param)
+{
+    pj_bzero(param, sizeof(*param));
+    param->restart_listener = PJ_TRUE;
+    param->restart_lis_delay = PJSUA_TRANSPORT_RESTART_DELAY_TIME;
 }
 
@@ -3272,2 +3344,243 @@
 }
 
+
+/* Forward declaration. */
+static void restart_listener_cb(void *user_data);
+
+
+static pj_status_t handle_ip_change_on_acc()
+{
+    int i = 0;
+    pj_status_t status = PJ_SUCCESS;
+    pj_bool_t acc_done[PJSUA_MAX_ACC];
+
+    /* Reset ip_change_active flag. */
+    for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	pjsua_var.acc[i].ip_change_op = PJSUA_IP_CHANGE_OP_NULL;
+	acc_done[i] = PJ_FALSE;
+    }    
+    
+    for (i = 0; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
+	pj_bool_t shutdown_transport = PJ_FALSE;
+	pjsip_regc_info regc_info;
+	char acc_id[PJSUA_MAX_ACC * 4];
+	pjsua_acc *acc = &pjsua_var.acc[i];
+	pjsip_transport *transport = NULL;
+	pjsua_acc_id shut_acc_ids[PJSUA_MAX_ACC];
+	unsigned shut_acc_cnt = 0;
+
+	if (!acc->valid || (acc_done[i]))
+	    continue;
+
+	if (acc->regc) {	    	    
+	    pjsip_regc_get_info(acc->regc, &regc_info);
+	    if ((regc_info.transport) &&
+		((regc_info.transport->flag & PJSIP_TRANSPORT_DATAGRAM) == 0))
+	    {
+		transport = regc_info.transport;
+		shutdown_transport = acc->cfg.ip_change_cfg.shutdown_tp;
+		shut_acc_ids[shut_acc_cnt++] = acc->index;
+	    }	
+	} else if (acc->reg_last_code != PJSIP_SC_BAD_GATEWAY &&
+		   acc->reg_last_code != PJSIP_SC_REQUEST_TIMEOUT &&
+		   acc->reg_last_code != PJSIP_SC_INTERNAL_SERVER_ERROR &&
+		   acc->reg_last_code != PJSIP_SC_BAD_GATEWAY &&
+		   acc->reg_last_code != PJSIP_SC_SERVICE_UNAVAILABLE &&
+		   acc->reg_last_code != PJSIP_SC_SERVER_TIMEOUT &&
+		   acc->reg_last_code != PJSIP_SC_TEMPORARILY_UNAVAILABLE) 
+	{
+	    continue;
+	} 
+	pj_ansi_snprintf(acc_id, sizeof(acc_id), "#%d", i);	
+
+	if (transport) {
+	    unsigned j = i + 1;
+
+	    /* Find other account that uses the same transport. */
+	    for (; j < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++j) {
+		pjsip_regc_info tmp_regc_info;
+		pjsua_acc *next_acc = &pjsua_var.acc[j];
+
+		if (!next_acc->valid || !next_acc->regc ||
+		    (next_acc->ip_change_op > PJSUA_IP_CHANGE_OP_NULL)) 
+		{
+		    continue;
+		}
+
+		pjsip_regc_get_info(next_acc->regc, &tmp_regc_info);
+		if (transport == tmp_regc_info.transport) {
+                    char tmp_buf[PJSUA_MAX_ACC * 4];
+
+                    pj_ansi_strncpy(tmp_buf, acc_id, sizeof(acc_id));
+		    pj_ansi_snprintf(acc_id, sizeof(acc_id), "%s #%d", 
+				     tmp_buf, j);
+		    shut_acc_ids[shut_acc_cnt++] = j;
+		    if (!shutdown_transport) {
+			shutdown_transport =
+				    next_acc->cfg.ip_change_cfg.shutdown_tp;			    
+		    }
+		}
+	    }
+	}
+
+	if (shutdown_transport) {
+	    unsigned j;
+	    /* Shutdown the transport. */	    
+	    PJ_LOG(3, (THIS_FILE, "Shutdown transport %s used by account %s "
+		       "triggered by IP change", transport->obj_name, acc_id));
+
+	    for (j = 0; j < shut_acc_cnt; ++j) {
+		pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]];
+		tmp_acc->ip_change_op = PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP;
+		acc_done[shut_acc_ids[j]] = PJ_TRUE;
+	    }
+
+	    status = pjsip_transport_shutdown2(transport, PJ_TRUE);
+
+	    /* Report progress to each acc which uses the same transport. */
+	    for (j = 0; j < shut_acc_cnt; ++j) {
+		pjsua_acc *tmp_acc = &pjsua_var.acc[shut_acc_ids[j]];
+
+		if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+		    pjsua_ip_change_op_info info;
+
+		    pj_bzero(&info, sizeof(info));
+		    info.acc_shutdown_tp.acc_id = tmp_acc->index;
+
+		    pjsua_var.ua_cfg.cb.on_ip_change_progress(
+							 tmp_acc->ip_change_op,
+							 status,
+							 &info);
+		}
+
+	    }
+	} else {
+	    acc_done[i] = PJ_TRUE;
+	    if (acc->cfg.allow_contact_rewrite) {
+		status = pjsua_acc_update_contact_on_ip_change(acc);
+	    } else {
+		status = pjsua_acc_handle_call_on_ip_change(acc);
+	    }
+	}
+    }
+    return status;
+}
+
+
+static pj_status_t restart_listener(pjsua_transport_id id, 
+				    unsigned restart_lis_delay)
+{
+    pj_sockaddr bind_addr;
+    pjsua_transport_info tp_info;
+    pj_status_t status;    
+
+    pjsua_transport_get_info(id, &tp_info);        
+    pj_sockaddr_init(pjsip_transport_type_get_af(tp_info.type),
+		     &bind_addr,
+		     NULL,
+		     pj_sockaddr_get_port(&tp_info.local_addr));
+    
+    switch (tp_info.type) {
+    case PJSIP_TRANSPORT_UDP:
+    case PJSIP_TRANSPORT_UDP6:
+	status = pjsip_udp_transport_restart2(
+				       pjsua_var.tpdata[id].data.tp,
+				       PJSIP_UDP_TRANSPORT_DESTROY_SOCKET,
+				       PJ_INVALID_SOCKET,
+				       &bind_addr,
+				       NULL);
+	break;
+
+#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
+    case PJSIP_TRANSPORT_TLS:
+    case PJSIP_TRANSPORT_TLS6:
+	status = pjsip_tls_transport_restart(
+					pjsua_var.tpdata[id].data.factory,
+					&bind_addr,
+					NULL);
+	break;
+#endif
+    case PJSIP_TRANSPORT_TCP:
+    case PJSIP_TRANSPORT_TCP6:
+	status = pjsip_tcp_transport_restart(
+					pjsua_var.tpdata[id].data.factory,
+					&bind_addr,
+					NULL);
+	break;
+
+    default:
+	status = PJ_EINVAL;
+    }
+    if (status != PJ_SUCCESS && (restart_lis_delay > 0)) {
+	/* Try restarting again, with delay. */
+	pjsua_schedule_timer2(&restart_listener_cb, 
+			      (void*)(pj_size_t)id, 
+			      restart_lis_delay);
+    } else {
+	int i = 0;
+	pj_bool_t all_done = PJ_TRUE;
+
+	pjsua_var.tpdata[id].is_restarting = PJ_FALSE;	
+	if (pjsua_var.ua_cfg.cb.on_ip_change_progress) {
+	    pjsua_ip_change_op_info info;
+
+	    pj_bzero(&info, sizeof(info));
+	    info.lis_restart.transport_id = id;
+	    pjsua_var.ua_cfg.cb.on_ip_change_progress(
+						PJSUA_IP_CHANGE_OP_RESTART_LIS, 
+						status, 
+						&info);
+	}
+
+	/* Move forward if all listener has been restarted. */
+	for (; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+	    if (pjsua_var.tpdata[i].data.ptr != NULL && 
+		pjsua_var.tpdata[i].is_restarting) 
+	    {
+		all_done = PJ_FALSE;
+		break;
+	    }
+	}
+	if (all_done)
+	    status = handle_ip_change_on_acc();
+    }
+    return status;
+}
+
+
+static void restart_listener_cb(void *user_data)
+{
+    pjsua_transport_id transport_id = (pjsua_transport_id)(pj_size_t)user_data;
+    restart_listener(transport_id, 0);
+}
+
+
+PJ_DEF(pj_status_t) pjsua_handle_ip_change(const pjsua_ip_change_param *param)
+{
+    pj_status_t status = PJ_SUCCESS;
+    int i = 0;
+
+    PJ_ASSERT_RETURN(param, PJ_EINVAL);
+
+    PJ_LOG(3, (THIS_FILE, "Start handling IP address change"));
+    
+    if (param->restart_listener) {
+	/* Restart listener/transport, handle_ip_change_on_acc() will
+	 * be called after listener restart is completed successfully.
+	 */
+	for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+	    if (pjsua_var.tpdata[i].data.ptr != NULL) {
+		pjsua_var.tpdata[i].is_restarting = PJ_TRUE;
+	    }
+	}
+	for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
+	    if (pjsua_var.tpdata[i].data.ptr != NULL) {		
+		status = restart_listener(i, param->restart_lis_delay);
+	    }
+	}
+    } else {
+	status = handle_ip_change_on_acc();
+    }
+
+    return status;
+}
Index: /pjproject/trunk/pjsip/src/pjsua2/account.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsua2/account.cpp	(revision 5649)
@@ -300,4 +300,23 @@
     NODE_WRITE_UNSIGNED( this_node, startKeyframeInterval);
 }
+///////////////////////////////////////////////////////////////////////////////
+
+void AccountIpChangeConfig::readObject(const ContainerNode &node) throw(Error)
+{
+    ContainerNode this_node = node.readContainer("AccountIpChangeConfig");
+
+    NODE_READ_BOOL    ( this_node, shutdownTp);
+    NODE_READ_BOOL    ( this_node, hangupCalls);
+    NODE_READ_UNSIGNED( this_node, reinviteFlags);
+}
+
+void AccountIpChangeConfig::writeObject(ContainerNode &node) const throw(Error)
+{
+    ContainerNode this_node = node.writeNewContainer("AccountIpChangeConfig");
+
+    NODE_WRITE_BOOL    ( this_node, shutdownTp);
+    NODE_WRITE_BOOL    ( this_node, hangupCalls);
+    NODE_WRITE_UNSIGNED( this_node, reinviteFlags);
+}
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -446,4 +465,9 @@
     ret.vid_stream_sk_cfg.count = videoConfig.startKeyframeCount;
     ret.vid_stream_sk_cfg.interval = videoConfig.startKeyframeInterval;
+
+    // AccountIpChangeConfig
+    ret.ip_change_cfg.shutdown_tp = ipChangeConfig.shutdownTp;
+    ret.ip_change_cfg.hangup_calls = ipChangeConfig.hangupCalls;
+    ret.ip_change_cfg.reinvite_flags = ipChangeConfig.reinviteFlags;
 }
 
@@ -615,4 +639,9 @@
     videoConfig.startKeyframeCount	= prm.vid_stream_sk_cfg.count;
     videoConfig.startKeyframeInterval	= prm.vid_stream_sk_cfg.interval;
+
+    // AccountIpChangeConfig
+    ipChangeConfig.shutdownTp = PJ2BOOL(prm.ip_change_cfg.shutdown_tp);
+    ipChangeConfig.hangupCalls = PJ2BOOL(prm.ip_change_cfg.hangup_calls);
+    ipChangeConfig.reinviteFlags = prm.ip_change_cfg.reinvite_flags;
 }
 
Index: /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5648)
+++ /pjproject/trunk/pjsip/src/pjsua2/endpoint.cpp	(revision 5649)
@@ -123,5 +123,31 @@
 
 ///////////////////////////////////////////////////////////////////////////////
-
+IpChangeParam::IpChangeParam()
+{
+    pjsua_ip_change_param param;    
+    pjsua_ip_change_param_default(&param);
+    fromPj(param);
+}
+
+
+pjsua_ip_change_param IpChangeParam::toPj() const
+{
+    pjsua_ip_change_param param;
+    pjsua_ip_change_param_default(&param);
+
+    param.restart_listener = restartListener;
+    param.restart_lis_delay = restartLisDelay;
+
+    return param;
+}
+
+
+void IpChangeParam::fromPj(const pjsua_ip_change_param &param)
+{
+    restartListener = PJ2BOOL(param.restart_listener);
+    restartLisDelay = param.restart_lis_delay;
+}
+
+///////////////////////////////////////////////////////////////////////////////
 UaConfig::UaConfig()
 : mainThreadOnly(false)
@@ -1407,4 +1433,41 @@
 }
 
+void Endpoint::on_ip_change_progress(pjsua_ip_change_op op,
+				     pj_status_t status,
+				     const pjsua_ip_change_op_info *info)
+{
+    Endpoint &ep = Endpoint::instance();
+    OnIpChangeProgressParam param;
+
+    param.op = op;
+    param.status = status;
+    switch (op) {
+    case PJSUA_IP_CHANGE_OP_RESTART_LIS:		
+	param.transportId = info->lis_restart.transport_id;	
+	break;
+    case PJSUA_IP_CHANGE_OP_ACC_SHUTDOWN_TP:
+	param.accId = info->acc_shutdown_tp.acc_id;
+	break;
+    case PJSUA_IP_CHANGE_OP_ACC_UPDATE_CONTACT:	
+	param.accId = info->acc_update_contact.acc_id;	
+	param.regInfo.code = info->acc_update_contact.code;
+	param.regInfo.isRegister = 
+				 PJ2BOOL(info->acc_update_contact.is_register);
+	break;
+    case PJSUA_IP_CHANGE_OP_ACC_HANGUP_CALLS:
+	param.accId = info->acc_hangup_calls.acc_id;
+	param.callId = info->acc_hangup_calls.call_id;
+	break;
+    case PJSUA_IP_CHANGE_OP_ACC_REINVITE_CALLS:
+	param.accId = info->acc_reinvite_calls.acc_id;
+	param.callId = info->acc_reinvite_calls.call_id;
+	break;
+    default:
+        param.accId = PJSUA_INVALID_ID;
+        break;
+    }
+    ep.onIpChangeProgress(param);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 /*
@@ -1469,4 +1532,5 @@
     ua_cfg.cb.on_buddy_state	= &Endpoint::on_buddy_state;
     ua_cfg.cb.on_acc_find_for_incoming  = &Endpoint::on_acc_find_for_incoming;
+    ua_cfg.cb.on_ip_change_progress	= &Endpoint::on_ip_change_progress;
 
     /* Call callbacks */
@@ -1989,2 +2053,8 @@
 #endif	
 }
+
+void Endpoint::handleIpChange(const IpChangeParam &param) throw(Error)
+{
+    pjsua_ip_change_param ip_change_param = param.toPj();
+    PJSUA2_CHECK_EXPR(pjsua_handle_ip_change(&ip_change_param));
+}
