PJ_DEF(pj_status_t) pjsip_process_route_set(pjsip_tx_data *tdata,
					    pjsip_host_info *dest_info )
{
    const pjsip_uri *new_request_uri, *target_uri;
    const pjsip_name_addr *topmost_route_uri;
    pjsip_route_hdr *first_route_hdr, *last_route_hdr;
    pj_status_t status;
    
    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, 
		     PJSIP_ENOTREQUESTMSG);
    PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL);

    /* If the request contains strict route, check that the strict route
     * has been restored to its original values before processing the
     * route set. The strict route is restored to the original values
     * with pjsip_restore_strict_route_set(). If caller did not restore
     * the strict route before calling this function, we need to call it
     * here, or otherwise the strict-route and Request-URI will be swapped
     * twice!
     */
    if (tdata->saved_strict_route != NULL) {
	pjsip_restore_strict_route_set(tdata);
    }
    PJ_ASSERT_RETURN(tdata->saved_strict_route==NULL, PJ_EBUG);

    /* Find the first and last "Route" headers from the message. */
    last_route_hdr = first_route_hdr = (pjsip_route_hdr*)
	pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);
    if (first_route_hdr) {
	topmost_route_uri = &first_route_hdr->name_addr;
	while (last_route_hdr->next != (void*)&tdata->msg->hdr) {
	    pjsip_route_hdr *hdr;
	    hdr = (pjsip_route_hdr*)
	    	  pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, 
                                     last_route_hdr->next);
	    if (!hdr)
		break;
	    last_route_hdr = hdr;
	}
    } else {
	topmost_route_uri = NULL;
    }

    /* If Route headers exist, and the first element indicates loose-route,
     * the URI is taken from the Request-URI, and we keep all existing Route
     * headers intact.
     * If Route headers exist, and the first element DOESN'T indicate loose
     * route, the URI is taken from the first Route header, and remove the
     * first Route header from the message.
     * Otherwise if there's no Route headers, the URI is taken from the
     * Request-URI.
     */
    if (topmost_route_uri) {
	pj_bool_t has_lr_param;

	if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) ||
	    PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri))
	{
	    const pjsip_sip_uri *url = (const pjsip_sip_uri*)
		pjsip_uri_get_uri((const void*)topmost_route_uri);
	    has_lr_param = url->lr_param;
	} else {
	    has_lr_param = 0;
	}

	if (has_lr_param) {
	    new_request_uri = tdata->msg->line.req.uri;
	    /* We shouldn't need to delete topmost Route if it has lr param.
	     * But seems like it breaks some proxy implementation, so we
	     * delete it anyway.
	     */
	    /*
	    pj_list_erase(first_route_hdr);
	    if (first_route_hdr == last_route_hdr)
		last_route_hdr = NULL;
	    */
	} else {
	    new_request_uri = (const pjsip_uri*) 
	    		      pjsip_uri_get_uri((pjsip_uri*)topmost_route_uri);
	    pj_list_erase(first_route_hdr);
	    tdata->saved_strict_route = first_route_hdr;
	    if (first_route_hdr == last_route_hdr)
		first_route_hdr = last_route_hdr = NULL;
	}

	target_uri = (pjsip_uri*)topmost_route_uri;

    } else {
	target_uri = new_request_uri = tdata->msg->line.req.uri;
    }

    /* Fill up the destination host/port from the URI. */
    status = pjsip_get_dest_info(target_uri, new_request_uri, tdata->pool,
			   	 dest_info);
    if (status != PJ_SUCCESS)
	return status;

    /* If transport selector is set, set destination type accordingly */
    if (tdata->tp_sel.type != PJSIP_TPSELECTOR_NONE && tdata->tp_sel.u.ptr) {
	if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT)
	    dest_info->type = tdata->tp_sel.u.transport->key.type;
	else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER)
	    dest_info->type = tdata->tp_sel.u.listener->type;
    }

    /* If target URI is different than request URI, replace 
     * request URI add put the original URI in the last Route header.
     */
    if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) {
	pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool);
	route->name_addr.uri = (pjsip_uri*) 
			       pjsip_uri_get_uri(tdata->msg->line.req.uri);
	if (last_route_hdr)
	    pj_list_insert_after(last_route_hdr, route);
	else
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route);
	tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri;
    }

    /* Success. */
    return PJ_SUCCESS;  
}
PJ_DEF(pj_status_t) pjsip_process_route_set(pjsip_tx_data *tdata,
					    pjsip_host_info *dest_info )
{
    const pjsip_uri *new_request_uri, *target_uri;
    const pjsip_name_addr *topmost_route_uri;
    pjsip_route_hdr *first_route_hdr, *last_route_hdr;
    pj_status_t status;
    
    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, 
		     PJSIP_ENOTREQUESTMSG);
    PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL);

     
    if (tdata->saved_strict_route != NULL) {
	pjsip_restore_strict_route_set(tdata);
    }
    PJ_ASSERT_RETURN(tdata->saved_strict_route==NULL, PJ_EBUG);

     
    last_route_hdr = first_route_hdr = (pjsip_route_hdr*)
	pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);
    if (first_route_hdr) {
	topmost_route_uri = &first_route_hdr->name_addr;
	while (last_route_hdr->next != (void*)&tdata->msg->hdr) {
	    pjsip_route_hdr *hdr;
	    hdr = (pjsip_route_hdr*)
	    	  pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, 
                                     last_route_hdr->next);
	    if (!hdr)
		break;
	    last_route_hdr = hdr;
	}
    } else {
	topmost_route_uri = NULL;
    }

     
    if (topmost_route_uri) {
	pj_bool_t has_lr_param;

	if (PJSIP_URI_SCHEME_IS_SIP(topmost_route_uri) ||
	    PJSIP_URI_SCHEME_IS_SIPS(topmost_route_uri))
	{
	    const pjsip_sip_uri *url = (const pjsip_sip_uri*)
		pjsip_uri_get_uri((const void*)topmost_route_uri);
	    has_lr_param = url->lr_param;
	} else {
	    has_lr_param = 0;
	}

	if (has_lr_param) {
	    new_request_uri = tdata->msg->line.req.uri;
	     
	     
	} else {
	    new_request_uri = (const pjsip_uri*) 
	    		      pjsip_uri_get_uri((pjsip_uri*)topmost_route_uri);
	    pj_list_erase(first_route_hdr);
	    tdata->saved_strict_route = first_route_hdr;
	    if (first_route_hdr == last_route_hdr)
		first_route_hdr = last_route_hdr = NULL;
	}

	target_uri = (pjsip_uri*)topmost_route_uri;

    } else {
	target_uri = new_request_uri = tdata->msg->line.req.uri;
    }

     
    status = pjsip_get_dest_info(target_uri, new_request_uri, tdata->pool,
			   	 dest_info);
    if (status != PJ_SUCCESS)
	return status;

     
    if (tdata->tp_sel.type != PJSIP_TPSELECTOR_NONE && tdata->tp_sel.u.ptr) {
	if (tdata->tp_sel.type == PJSIP_TPSELECTOR_TRANSPORT)
	    dest_info->type = tdata->tp_sel.u.transport->key.type;
	else if (tdata->tp_sel.type == PJSIP_TPSELECTOR_LISTENER)
	    dest_info->type = tdata->tp_sel.u.listener->type;
    }

     
    if (new_request_uri && new_request_uri!=tdata->msg->line.req.uri) {
	pjsip_route_hdr *route = pjsip_route_hdr_create(tdata->pool);
	route->name_addr.uri = (pjsip_uri*) 
			       pjsip_uri_get_uri(tdata->msg->line.req.uri);
	if (last_route_hdr)
	    pj_list_insert_after(last_route_hdr, route);
	else
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route);
	tdata->msg->line.req.uri = (pjsip_uri*)new_request_uri;
    }

     
    return PJ_SUCCESS;  
}