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);

    for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
	if (pjsua_var.acc[i].valid &&
	    pjsua_var.acc[i].ip_change_op != PJSUA_IP_CHANGE_OP_NULL &&
	    pjsua_var.acc[i].ip_change_op != PJSUA_IP_CHANGE_OP_COMPLETED)
	{
	    PJ_LOG(2, (THIS_FILE,
		     "Previous IP address change handling still in progress"));
	}
    }

    PJ_LOG(3, (THIS_FILE, "Start handling IP address change"));

    /* Avoid call disconnection due to request timeout. Some requests may
     * be in progress when network is changing, they may eventually get
     * timed out and cause call disconnection.
     */
    if (!pjsip_cfg()->endpt.keep_inv_after_tsx_timeout) {
	pjsip_cfg()->endpt.keep_inv_after_tsx_timeout = PJ_TRUE;

	/* Put it back after some time (transaction timeout setting value) */
	pjsua_schedule_timer2(&ip_change_put_back_inv_config, NULL,
			      pjsip_cfg()->tsx.td);

	PJ_LOG(4,(THIS_FILE,"IP change temporarily ignores request timeout"));
    }

    if (param->restart_listener) {
	PJSUA_LOCK();
	/* 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;
		pjsua_var.tpdata[i].restart_status = PJ_EUNKNOWN;
	    }
	}
	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);
	    }
	}
        PJSUA_UNLOCK();
    } else {
	for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
	    if (pjsua_var.tpdata[i].data.ptr != NULL) {
		pjsua_var.tpdata[i].restart_status = PJ_SUCCESS;
	    }
	}
	status = handle_ip_change_on_acc();
    }

    return status;
}
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);

    for (; i < (int)PJ_ARRAY_SIZE(pjsua_var.acc); ++i) {
	if (pjsua_var.acc[i].valid &&
	    pjsua_var.acc[i].ip_change_op != PJSUA_IP_CHANGE_OP_NULL &&
	    pjsua_var.acc[i].ip_change_op != PJSUA_IP_CHANGE_OP_COMPLETED)
	{
	    PJ_LOG(2, (THIS_FILE,
		     "Previous IP address change handling still in progress"));
	}
    }

    PJ_LOG(3, (THIS_FILE, "Start handling IP address change"));

     
    if (!pjsip_cfg()->endpt.keep_inv_after_tsx_timeout) {
	pjsip_cfg()->endpt.keep_inv_after_tsx_timeout = PJ_TRUE;

	 
	pjsua_schedule_timer2(&ip_change_put_back_inv_config, NULL,
			      pjsip_cfg()->tsx.td);

	PJ_LOG(4,(THIS_FILE,"IP change temporarily ignores request timeout"));
    }

    if (param->restart_listener) {
	PJSUA_LOCK();
	 
	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;
		pjsua_var.tpdata[i].restart_status = PJ_EUNKNOWN;
	    }
	}
	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);
	    }
	}
        PJSUA_UNLOCK();
    } else {
	for (i = 0; i < PJ_ARRAY_SIZE(pjsua_var.tpdata); ++i) {
	    if (pjsua_var.tpdata[i].data.ptr != NULL) {
		pjsua_var.tpdata[i].restart_status = PJ_SUCCESS;
	    }
	}
	status = handle_ip_change_on_acc();
    }

    return status;
}