* #39226: Switch back to pjsip rev 4710

Rev 4716 introduces errors when building for android (miltiple definitions)
diff --git a/jni/pjproject-android/.svn/pristine/f5/f53ffd84f2beec564aaf2fb738d353933f77e0fd.svn-base b/jni/pjproject-android/.svn/pristine/f5/f53ffd84f2beec564aaf2fb738d353933f77e0fd.svn-base
new file mode 100644
index 0000000..520d873
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f53ffd84f2beec564aaf2fb738d353933f77e0fd.svn-base
@@ -0,0 +1,1872 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pjsip/sip_util.h>
+#include <pjsip/sip_transport.h>
+#include <pjsip/sip_msg.h>
+#include <pjsip/sip_endpoint.h>
+#include <pjsip/sip_event.h>
+#include <pjsip/sip_transaction.h>
+#include <pjsip/sip_module.h>
+#include <pjsip/sip_errno.h>
+#include <pj/log.h>
+#include <pj/string.h>
+#include <pj/guid.h>
+#include <pj/pool.h>
+#include <pj/except.h>
+#include <pj/rand.h>
+#include <pj/assert.h>
+#include <pj/errno.h>
+
+#define THIS_FILE    "endpoint"
+
+static const char *event_str[] = 
+{
+    "UNIDENTIFIED",
+    "TIMER",
+    "TX_MSG",
+    "RX_MSG",
+    "TRANSPORT_ERROR",
+    "TSX_STATE",
+    "USER",
+};
+
+static pj_str_t str_TEXT = { "text", 4},
+		str_PLAIN = { "plain", 5 };
+
+/* Add URI to target-set */
+PJ_DEF(pj_status_t) pjsip_target_set_add_uri( pjsip_target_set *tset,
+					      pj_pool_t *pool,
+					      const pjsip_uri *uri,
+					      int q1000)
+{
+    pjsip_target *t, *pos = NULL;
+
+    PJ_ASSERT_RETURN(tset && pool && uri, PJ_EINVAL);
+
+    /* Set q-value to 1 if it is not set */
+    if (q1000 <= 0)
+	q1000 = 1000;
+
+    /* Scan all the elements to see for duplicates, and at the same time
+     * get the position where the new element should be inserted to
+     * based on the q-value.
+     */
+    t = tset->head.next;
+    while (t != &tset->head) {
+	if (pjsip_uri_cmp(PJSIP_URI_IN_REQ_URI, t->uri, uri)==PJ_SUCCESS)
+	    return PJ_EEXISTS;
+	if (pos==NULL && t->q1000 < q1000)
+	    pos = t;
+	t = t->next;
+    }
+
+    /* Create new element */
+    t = PJ_POOL_ZALLOC_T(pool, pjsip_target);
+    t->uri = (pjsip_uri*)pjsip_uri_clone(pool, uri);
+    t->q1000 = q1000;
+
+    /* Insert */
+    if (pos == NULL)
+	pj_list_push_back(&tset->head, t);
+    else
+	pj_list_insert_before(pos, t);
+
+    /* Set current target if this is the first URI */
+    if (tset->current == NULL)
+	tset->current = t;
+
+    return PJ_SUCCESS;
+}
+
+/* Add URI's in the Contact header in the message to target-set */
+PJ_DEF(pj_status_t) pjsip_target_set_add_from_msg( pjsip_target_set *tset,
+						   pj_pool_t *pool,
+						   const pjsip_msg *msg)
+{
+    const pjsip_hdr *hdr;
+    unsigned added = 0;
+
+    PJ_ASSERT_RETURN(tset && pool && msg, PJ_EINVAL);
+
+    /* Scan for Contact headers and add the URI */
+    hdr = msg->hdr.next;
+    while (hdr != &msg->hdr) {
+	if (hdr->type == PJSIP_H_CONTACT) {
+	    const pjsip_contact_hdr *cn_hdr = (const pjsip_contact_hdr*)hdr;
+
+	    if (!cn_hdr->star) {
+		pj_status_t rc;
+		rc = pjsip_target_set_add_uri(tset, pool, cn_hdr->uri, 
+					      cn_hdr->q1000);
+		if (rc == PJ_SUCCESS)
+		    ++added;
+	    }
+	}
+	hdr = hdr->next;
+    }
+
+    return added ? PJ_SUCCESS : PJ_EEXISTS;
+}
+
+
+/* Get next target, if any */
+PJ_DEF(pjsip_target*) pjsip_target_set_get_next(const pjsip_target_set *tset)
+{
+    const pjsip_target *t, *next = NULL;
+
+    t = tset->head.next;
+    while (t != &tset->head) {
+	if (PJSIP_IS_STATUS_IN_CLASS(t->code, 200)) {
+	    /* No more target since one target has been successful */
+	    return NULL;
+	}
+	if (PJSIP_IS_STATUS_IN_CLASS(t->code, 600)) {
+	    /* No more target since one target returned global error */
+	    return NULL;
+	}
+	if (t->code==0 && next==NULL) {
+	    /* This would be the next target as long as we don't find
+	     * targets with 2xx or 6xx status after this.
+	     */
+	    next = t;
+	}
+	t = t->next;
+    }
+
+    return (pjsip_target*)next;
+}
+
+
+/* Set current target */
+PJ_DEF(pj_status_t) pjsip_target_set_set_current( pjsip_target_set *tset,
+						  pjsip_target *target)
+{
+    PJ_ASSERT_RETURN(tset && target, PJ_EINVAL);
+    PJ_ASSERT_RETURN(pj_list_find_node(tset, target) != NULL, PJ_ENOTFOUND);
+
+    tset->current = target;
+
+    return PJ_SUCCESS;
+}
+
+
+/* Assign status to a target */
+PJ_DEF(pj_status_t) pjsip_target_assign_status( pjsip_target *target,
+					        pj_pool_t *pool,
+					        int status_code,
+					        const pj_str_t *reason)
+{
+    PJ_ASSERT_RETURN(target && pool && status_code && reason, PJ_EINVAL);
+
+    target->code = (pjsip_status_code)status_code;
+    pj_strdup(pool, &target->reason, reason);
+
+    return PJ_SUCCESS;
+}
+
+
+
+/*
+ * Initialize transmit data (msg) with the headers and optional body.
+ * This will just put the headers in the message as it is. Be carefull
+ * when calling this function because once a header is put in a message, 
+ * it CAN NOT be put in other message until the first message is deleted, 
+ * because the way the header is put in the list.
+ * That's why the session will shallow_clone it's headers before calling
+ * this function.
+ */
+static void init_request_throw( pjsip_endpoint *endpt,
+                                pjsip_tx_data *tdata, 
+				pjsip_method *method,
+				pjsip_uri *param_target,
+				pjsip_from_hdr *param_from,
+				pjsip_to_hdr *param_to, 
+				pjsip_contact_hdr *param_contact,
+				pjsip_cid_hdr *param_call_id,
+				pjsip_cseq_hdr *param_cseq, 
+				const pj_str_t *param_text)
+{
+    pjsip_msg *msg;
+    pjsip_msg_body *body;
+    pjsip_via_hdr *via;
+    const pjsip_hdr *endpt_hdr;
+
+    /* Create the message. */
+    msg = tdata->msg = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);
+
+    /* Init request URI. */
+    pj_memcpy(&msg->line.req.method, method, sizeof(*method));
+    msg->line.req.uri = param_target;
+
+    /* Add additional request headers from endpoint. */
+    endpt_hdr = pjsip_endpt_get_request_headers(endpt)->next;
+    while (endpt_hdr != pjsip_endpt_get_request_headers(endpt)) {
+	pjsip_hdr *hdr = (pjsip_hdr*) 
+			 pjsip_hdr_shallow_clone(tdata->pool, endpt_hdr);
+	pjsip_msg_add_hdr( tdata->msg, hdr );
+	endpt_hdr = endpt_hdr->next;
+    }
+
+    /* Add From header. */
+    if (param_from->tag.slen == 0)
+	pj_create_unique_string(tdata->pool, &param_from->tag);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)param_from);
+
+    /* Add To header. */
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)param_to);
+
+    /* Add Contact header. */
+    if (param_contact) {
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*)param_contact);
+    }
+
+    /* Add Call-ID header. */
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)param_call_id);
+
+    /* Add CSeq header. */
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*)param_cseq);
+
+    /* Add a blank Via header in the front of the message. */
+    via = pjsip_via_hdr_create(tdata->pool);
+    via->rport_param = pjsip_cfg()->endpt.disable_rport ? -1 : 0;
+    pjsip_msg_insert_first_hdr(msg, (pjsip_hdr*)via);
+
+    /* Add header params as request headers */
+    if (PJSIP_URI_SCHEME_IS_SIP(param_target) || 
+	PJSIP_URI_SCHEME_IS_SIPS(param_target)) 
+    {
+	pjsip_sip_uri *uri = (pjsip_sip_uri*) pjsip_uri_get_uri(param_target);
+	pjsip_param *hparam;
+
+	hparam = uri->header_param.next;
+	while (hparam != &uri->header_param) {
+	    pjsip_generic_string_hdr *hdr;
+
+	    hdr = pjsip_generic_string_hdr_create(tdata->pool, 
+						  &hparam->name,
+						  &hparam->value);
+	    pjsip_msg_add_hdr(msg, (pjsip_hdr*)hdr);
+	    hparam = hparam->next;
+	}
+    }
+
+    /* Create message body. */
+    if (param_text) {
+	body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
+	body->content_type.type = str_TEXT;
+	body->content_type.subtype = str_PLAIN;
+	body->data = pj_pool_alloc(tdata->pool, param_text->slen );
+	pj_memcpy(body->data, param_text->ptr, param_text->slen);
+	body->len = (unsigned)param_text->slen;
+	body->print_body = &pjsip_print_text_body;
+	msg->body = body;
+    }
+
+    PJ_LOG(5,(THIS_FILE, "%s created.", 
+			 pjsip_tx_data_get_info(tdata)));
+
+}
+
+/*
+ * Create arbitrary request.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_request(  pjsip_endpoint *endpt, 
+						 const pjsip_method *method,
+						 const pj_str_t *param_target,
+						 const pj_str_t *param_from,
+						 const pj_str_t *param_to, 
+						 const pj_str_t *param_contact,
+						 const pj_str_t *param_call_id,
+						 int param_cseq, 
+						 const pj_str_t *param_text,
+						 pjsip_tx_data **p_tdata)
+{
+    pjsip_uri *target;
+    pjsip_tx_data *tdata;
+    pjsip_from_hdr *from;
+    pjsip_to_hdr *to;
+    pjsip_contact_hdr *contact;
+    pjsip_cseq_hdr *cseq = NULL;    /* = NULL, warning in VC6 */
+    pjsip_cid_hdr *call_id;
+    pj_str_t tmp;
+    pj_status_t status;
+    const pj_str_t STR_CONTACT = { "Contact", 7 };
+    PJ_USE_EXCEPTION;
+
+    status = pjsip_endpt_create_tdata(endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Init reference counter to 1. */
+    pjsip_tx_data_add_ref(tdata);
+
+    PJ_TRY {
+	/* Request target. */
+	pj_strdup_with_null(tdata->pool, &tmp, param_target);
+	target = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 0);
+	if (target == NULL) {
+	    status = PJSIP_EINVALIDREQURI;
+	    goto on_error;
+	}
+
+	/* From */
+	from = pjsip_from_hdr_create(tdata->pool);
+	pj_strdup_with_null(tdata->pool, &tmp, param_from);
+	from->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
+				     PJSIP_PARSE_URI_AS_NAMEADDR);
+	if (from->uri == NULL) {
+	    status = PJSIP_EINVALIDHDR;
+	    goto on_error;
+	}
+	pj_create_unique_string(tdata->pool, &from->tag);
+
+	/* To */
+	to = pjsip_to_hdr_create(tdata->pool);
+	pj_strdup_with_null(tdata->pool, &tmp, param_to);
+	to->uri = pjsip_parse_uri( tdata->pool, tmp.ptr, tmp.slen, 
+				   PJSIP_PARSE_URI_AS_NAMEADDR);
+	if (to->uri == NULL) {
+	    status = PJSIP_EINVALIDHDR;
+	    goto on_error;
+	}
+
+	/* Contact. */
+	if (param_contact) {
+	    pj_strdup_with_null(tdata->pool, &tmp, param_contact);
+	    contact = (pjsip_contact_hdr*)
+		      pjsip_parse_hdr(tdata->pool, &STR_CONTACT, tmp.ptr, 
+				      tmp.slen, NULL);
+	    if (contact == NULL) {
+		status = PJSIP_EINVALIDHDR;
+		goto on_error;
+	    }
+	} else {
+	    contact = NULL;
+	}
+
+	/* Call-ID */
+	call_id = pjsip_cid_hdr_create(tdata->pool);
+	if (param_call_id != NULL && param_call_id->slen)
+	    pj_strdup(tdata->pool, &call_id->id, param_call_id);
+	else
+	    pj_create_unique_string(tdata->pool, &call_id->id);
+
+	/* CSeq */
+	cseq = pjsip_cseq_hdr_create(tdata->pool);
+	if (param_cseq >= 0)
+	    cseq->cseq = param_cseq;
+	else
+	    cseq->cseq = pj_rand() & 0xFFFF;
+
+	/* Method */
+	pjsip_method_copy(tdata->pool, &cseq->method, method);
+
+	/* Create the request. */
+	init_request_throw( endpt, tdata, &cseq->method, target, from, to, 
+                            contact, call_id, cseq, param_text);
+    }
+    PJ_CATCH_ANY {
+	status = PJ_ENOMEM;
+	goto on_error;
+    }
+    PJ_END
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+
+on_error:
+    pjsip_tx_data_dec_ref(tdata);
+    return status;
+}
+
+PJ_DEF(pj_status_t) pjsip_endpt_create_request_from_hdr( pjsip_endpoint *endpt,
+				     const pjsip_method *method,
+				     const pjsip_uri *param_target,
+				     const pjsip_from_hdr *param_from,
+				     const pjsip_to_hdr *param_to,
+				     const pjsip_contact_hdr *param_contact,
+				     const pjsip_cid_hdr *param_call_id,
+				     int param_cseq,
+				     const pj_str_t *param_text,
+				     pjsip_tx_data **p_tdata)
+{
+    pjsip_uri *target;
+    pjsip_tx_data *tdata;
+    pjsip_from_hdr *from;
+    pjsip_to_hdr *to;
+    pjsip_contact_hdr *contact;
+    pjsip_cid_hdr *call_id;
+    pjsip_cseq_hdr *cseq = NULL; /* The NULL because warning in VC6 */
+    pj_status_t status;
+    PJ_USE_EXCEPTION;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(endpt && method && param_target && param_from &&
+		     param_to && p_tdata, PJ_EINVAL);
+
+    /* Create new transmit data. */
+    status = pjsip_endpt_create_tdata(endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Set initial reference counter to 1. */
+    pjsip_tx_data_add_ref(tdata);
+
+    PJ_TRY {
+	/* Duplicate target URI and headers. */
+	target = (pjsip_uri*) pjsip_uri_clone(tdata->pool, param_target);
+	from = (pjsip_from_hdr*) pjsip_hdr_clone(tdata->pool, param_from);
+	pjsip_fromto_hdr_set_from(from);
+	to = (pjsip_to_hdr*) pjsip_hdr_clone(tdata->pool, param_to);
+	pjsip_fromto_hdr_set_to(to);
+	if (param_contact) {
+	    contact = (pjsip_contact_hdr*) 
+	    	      pjsip_hdr_clone(tdata->pool, param_contact);
+	} else {
+	    contact = NULL;
+	}
+	call_id = pjsip_cid_hdr_create(tdata->pool);
+	if (param_call_id != NULL && param_call_id->id.slen)
+	    pj_strdup(tdata->pool, &call_id->id, &param_call_id->id);
+	else
+	    pj_create_unique_string(tdata->pool, &call_id->id);
+
+	cseq = pjsip_cseq_hdr_create(tdata->pool);
+	if (param_cseq >= 0)
+	    cseq->cseq = param_cseq;
+	else
+	    cseq->cseq = pj_rand() % 0xFFFF;
+	pjsip_method_copy(tdata->pool, &cseq->method, method);
+
+	/* Copy headers to the request. */
+	init_request_throw(endpt, tdata, &cseq->method, target, from, to, 
+                           contact, call_id, cseq, param_text);
+    }
+    PJ_CATCH_ANY {
+	status = PJ_ENOMEM;
+	goto on_error;
+    }
+    PJ_END;
+
+    *p_tdata = tdata;
+    return PJ_SUCCESS;
+
+on_error:
+    pjsip_tx_data_dec_ref(tdata);
+    return status;
+}
+
+/*
+ * Construct a minimal response message for the received request.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
+						 const pjsip_rx_data *rdata,
+						 int st_code,
+						 const pj_str_t *st_text,
+						 pjsip_tx_data **p_tdata)
+{
+    pjsip_tx_data *tdata;
+    pjsip_msg *msg, *req_msg;
+    pjsip_hdr *hdr;
+    pjsip_to_hdr *to_hdr;
+    pjsip_via_hdr *top_via = NULL, *via;
+    pjsip_rr_hdr *rr;
+    pj_status_t status;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL);
+
+    /* Check status code. */
+    PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);
+
+    /* rdata must be a request message. */
+    req_msg = rdata->msg_info.msg;
+    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);
+
+    /* Request MUST NOT be ACK request! */
+    PJ_ASSERT_RETURN(req_msg->line.req.method.id != PJSIP_ACK_METHOD,
+		     PJ_EINVALIDOP);
+
+    /* Create a new transmit buffer. */
+    status = pjsip_endpt_create_tdata( endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Set initial reference count to 1. */
+    pjsip_tx_data_add_ref(tdata);
+
+    /* Create new response message. */
+    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);
+
+    /* Set status code and reason text. */
+    msg->line.status.code = st_code;
+    if (st_text)
+	pj_strdup(tdata->pool, &msg->line.status.reason, st_text);
+    else
+	msg->line.status.reason = *pjsip_get_status_text(st_code);
+
+    /* Set TX data attributes. */
+    tdata->rx_timestamp = rdata->pkt_info.timestamp;
+
+    /* Copy all the via headers, in order. */
+    via = rdata->msg_info.via;
+    while (via) {
+	pjsip_via_hdr *new_via;
+
+	new_via = (pjsip_via_hdr*)pjsip_hdr_clone(tdata->pool, via);
+	if (top_via == NULL)
+	    top_via = new_via;
+
+	pjsip_msg_add_hdr( msg, (pjsip_hdr*)new_via);
+	via = via->next;
+	if (via != (void*)&req_msg->hdr)
+	    via = (pjsip_via_hdr*) 
+	    	  pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);
+	else
+	    break;
+    }
+
+    /* Copy all Record-Route headers, in order. */
+    rr = (pjsip_rr_hdr*) 
+    	 pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);
+    while (rr) {
+	pjsip_msg_add_hdr(msg, (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rr));
+	rr = rr->next;
+	if (rr != (void*)&req_msg->hdr)
+	    rr = (pjsip_rr_hdr*) pjsip_msg_find_hdr(req_msg, 
+	    					    PJSIP_H_RECORD_ROUTE, rr);
+	else
+	    break;
+    }
+
+    /* Copy Call-ID header. */
+    hdr = (pjsip_hdr*) pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);
+    pjsip_msg_add_hdr(msg, (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr));
+
+    /* Copy From header. */
+    hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.from);
+    pjsip_msg_add_hdr( msg, hdr);
+
+    /* Copy To header. */
+    to_hdr = (pjsip_to_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.to);
+    pjsip_msg_add_hdr( msg, (pjsip_hdr*)to_hdr);
+
+    /* Must add To tag in the response (Section 8.2.6.2), except if this is
+     * 100 (Trying) response. Same tag must be created for the same request
+     * (e.g. same tag in provisional and final response). The easiest way
+     * to do this is to derive the tag from Via branch parameter (or to
+     * use it directly).
+     */
+    if (to_hdr->tag.slen==0 && st_code > 100 && top_via) {
+	to_hdr->tag = top_via->branch_param;
+    }
+
+    /* Copy CSeq header. */
+    hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq);
+    pjsip_msg_add_hdr( msg, hdr);
+
+    /* All done. */
+    *p_tdata = tdata;
+
+    PJ_LOG(5,(THIS_FILE, "%s created", pjsip_tx_data_get_info(tdata)));
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Construct ACK for 3xx-6xx final response (according to chapter 17.1.1 of
+ * RFC3261). Note that the generation of ACK for 2xx response is different,
+ * and one must not use this function to generate such ACK.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_ack( pjsip_endpoint *endpt,
+					    const pjsip_tx_data *tdata,
+					    const pjsip_rx_data *rdata,
+					    pjsip_tx_data **ack_tdata)
+{
+    pjsip_tx_data *ack = NULL;
+    const pjsip_msg *invite_msg;
+    const pjsip_from_hdr *from_hdr;
+    const pjsip_to_hdr *to_hdr;
+    const pjsip_cid_hdr *cid_hdr;
+    const pjsip_cseq_hdr *cseq_hdr;
+    const pjsip_hdr *hdr;
+    pjsip_hdr *via;
+    pjsip_to_hdr *to;
+    pj_status_t status;
+
+    /* rdata must be a non-2xx final response. */
+    pj_assert(rdata->msg_info.msg->type==PJSIP_RESPONSE_MSG &&
+	      rdata->msg_info.msg->line.status.code >= 300);
+
+    /* Initialize return value to NULL. */
+    *ack_tdata = NULL;
+
+    /* The original INVITE message. */
+    invite_msg = tdata->msg;
+
+    /* Get the headers from original INVITE request. */
+#   define FIND_HDR(m,HNAME) pjsip_msg_find_hdr(m, PJSIP_H_##HNAME, NULL)
+
+    from_hdr = (const pjsip_from_hdr*) FIND_HDR(invite_msg, FROM);
+    PJ_ASSERT_ON_FAIL(from_hdr != NULL, goto on_missing_hdr);
+
+    to_hdr = (const pjsip_to_hdr*) FIND_HDR(invite_msg, TO);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+    cid_hdr = (const pjsip_cid_hdr*) FIND_HDR(invite_msg, CALL_ID);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+    cseq_hdr = (const pjsip_cseq_hdr*) FIND_HDR(invite_msg, CSEQ);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+#   undef FIND_HDR
+
+    /* Create new request message from the headers. */
+    status = pjsip_endpt_create_request_from_hdr(endpt, 
+						 pjsip_get_ack_method(),
+						 tdata->msg->line.req.uri,
+						 from_hdr, to_hdr,
+						 NULL, cid_hdr,
+						 cseq_hdr->cseq, NULL,
+						 &ack);
+
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Update tag in To header with the one from the response (if any). */
+    to = (pjsip_to_hdr*) pjsip_msg_find_hdr(ack->msg, PJSIP_H_TO, NULL);
+    pj_strdup(ack->pool, &to->tag, &rdata->msg_info.to->tag);
+
+
+    /* Clear Via headers in the new request. */
+    while ((via=(pjsip_hdr*)pjsip_msg_find_hdr(ack->msg, PJSIP_H_VIA, NULL)) != NULL)
+	pj_list_erase(via);
+
+    /* Must contain single Via, just as the original INVITE. */
+    hdr = (pjsip_hdr*) pjsip_msg_find_hdr( invite_msg, PJSIP_H_VIA, NULL);
+    pjsip_msg_insert_first_hdr( ack->msg, 
+    			        (pjsip_hdr*) pjsip_hdr_clone(ack->pool,hdr) );
+
+    /* If the original INVITE has Route headers, those header fields MUST 
+     * appear in the ACK.
+     */
+    hdr = (pjsip_hdr*) pjsip_msg_find_hdr( invite_msg, PJSIP_H_ROUTE, NULL);
+    while (hdr != NULL) {
+	pjsip_msg_add_hdr( ack->msg, 
+			   (pjsip_hdr*) pjsip_hdr_clone(ack->pool, hdr) );
+	hdr = hdr->next;
+	if (hdr == &invite_msg->hdr)
+	    break;
+	hdr = (pjsip_hdr*) pjsip_msg_find_hdr( invite_msg, PJSIP_H_ROUTE, hdr);
+    }
+
+    /* We're done.
+     * "tdata" parameter now contains the ACK message.
+     */
+    *ack_tdata = ack;
+    return PJ_SUCCESS;
+
+on_missing_hdr:
+    if (ack)
+	pjsip_tx_data_dec_ref(ack);
+    return PJSIP_EMISSINGHDR;
+}
+
+
+/*
+ * Construct CANCEL request for the previously sent request, according to
+ * chapter 9.1 of RFC3261.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_create_cancel( pjsip_endpoint *endpt,
+					       const pjsip_tx_data *req_tdata,
+					       pjsip_tx_data **p_tdata)
+{
+    pjsip_tx_data *cancel_tdata = NULL;
+    const pjsip_from_hdr *from_hdr;
+    const pjsip_to_hdr *to_hdr;
+    const pjsip_cid_hdr *cid_hdr;
+    const pjsip_cseq_hdr *cseq_hdr;
+    const pjsip_hdr *hdr;
+    pjsip_hdr *via;
+    pj_status_t status;
+
+    /* The transmit buffer must INVITE request. */
+    PJ_ASSERT_RETURN(req_tdata->msg->type == PJSIP_REQUEST_MSG &&
+		     req_tdata->msg->line.req.method.id == PJSIP_INVITE_METHOD,
+		     PJ_EINVAL);
+
+    /* Get the headers from original INVITE request. */
+#   define FIND_HDR(m,HNAME) pjsip_msg_find_hdr(m, PJSIP_H_##HNAME, NULL)
+
+    from_hdr = (const pjsip_from_hdr*) FIND_HDR(req_tdata->msg, FROM);
+    PJ_ASSERT_ON_FAIL(from_hdr != NULL, goto on_missing_hdr);
+
+    to_hdr = (const pjsip_to_hdr*) FIND_HDR(req_tdata->msg, TO);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+    cid_hdr = (const pjsip_cid_hdr*) FIND_HDR(req_tdata->msg, CALL_ID);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+    cseq_hdr = (const pjsip_cseq_hdr*) FIND_HDR(req_tdata->msg, CSEQ);
+    PJ_ASSERT_ON_FAIL(to_hdr != NULL, goto on_missing_hdr);
+
+#   undef FIND_HDR
+
+    /* Create new request message from the headers. */
+    status = pjsip_endpt_create_request_from_hdr(endpt, 
+						 pjsip_get_cancel_method(),
+						 req_tdata->msg->line.req.uri,
+						 from_hdr, to_hdr,
+						 NULL, cid_hdr,
+						 cseq_hdr->cseq, NULL,
+						 &cancel_tdata);
+
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Clear Via headers in the new request. */
+    while ((via=(pjsip_hdr*)pjsip_msg_find_hdr(cancel_tdata->msg, PJSIP_H_VIA, NULL)) != NULL)
+	pj_list_erase(via);
+
+
+    /* Must only have single Via which matches the top-most Via in the 
+     * request being cancelled. 
+     */
+    hdr = (pjsip_hdr*) pjsip_msg_find_hdr(req_tdata->msg, PJSIP_H_VIA, NULL);
+    if (hdr) {
+	pjsip_msg_insert_first_hdr(cancel_tdata->msg, 
+				   (pjsip_hdr*)pjsip_hdr_clone(cancel_tdata->pool, hdr));
+    }
+
+    /* If the original request has Route header, the CANCEL request must also
+     * has exactly the same.
+     * Copy "Route" header from the request.
+     */
+    hdr = (pjsip_hdr*) pjsip_msg_find_hdr(req_tdata->msg, PJSIP_H_ROUTE, NULL);
+    while (hdr != NULL) {
+	pjsip_msg_add_hdr(cancel_tdata->msg, 
+			  (pjsip_hdr*) pjsip_hdr_clone(cancel_tdata->pool, hdr));
+	hdr = hdr->next;
+	if (hdr != &req_tdata->msg->hdr)
+	    hdr = (pjsip_hdr*) pjsip_msg_find_hdr(req_tdata->msg, 
+	    					  PJSIP_H_ROUTE, hdr);
+	else
+	    break;
+    }
+
+    /* Must also copy the saved strict route header, otherwise CANCEL will be
+     * sent with swapped Route and request URI!
+     */
+    if (req_tdata->saved_strict_route) {
+	cancel_tdata->saved_strict_route = (pjsip_route_hdr*)
+	    pjsip_hdr_clone(cancel_tdata->pool, req_tdata->saved_strict_route);
+    }
+
+    /* Copy the destination host name from the original request */
+    pj_strdup(cancel_tdata->pool, &cancel_tdata->dest_info.name,
+	      &req_tdata->dest_info.name);
+
+    /* Finally copy the destination info from the original request */
+    pj_memcpy(&cancel_tdata->dest_info, &req_tdata->dest_info,
+	      sizeof(req_tdata->dest_info));
+
+    /* Done.
+     * Return the transmit buffer containing the CANCEL request.
+     */
+    *p_tdata = cancel_tdata;
+    return PJ_SUCCESS;
+
+on_missing_hdr:
+    if (cancel_tdata)
+	pjsip_tx_data_dec_ref(cancel_tdata);
+    return PJSIP_EMISSINGHDR;
+}
+
+
+/* Fill-up destination information from a target URI */
+static pj_status_t get_dest_info(const pjsip_uri *target_uri, 
+				 pj_pool_t *pool,
+				 pjsip_host_info *dest_info)
+{
+    /* The target URI must be a SIP/SIPS URL so we can resolve it's address.
+     * Otherwise we're in trouble (i.e. there's no host part in tel: URL).
+     */
+    pj_bzero(dest_info, sizeof(*dest_info));
+
+    if (PJSIP_URI_SCHEME_IS_SIPS(target_uri)) {
+	pjsip_uri *uri = (pjsip_uri*) target_uri;
+	const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri);
+	unsigned flag;
+
+	dest_info->flag |= (PJSIP_TRANSPORT_SECURE | PJSIP_TRANSPORT_RELIABLE);
+	if (url->maddr_param.slen)
+	    pj_strdup(pool, &dest_info->addr.host, &url->maddr_param);
+	else
+	    pj_strdup(pool, &dest_info->addr.host, &url->host);
+        dest_info->addr.port = url->port;
+	dest_info->type = 
+            pjsip_transport_get_type_from_name(&url->transport_param);
+	/* Double-check that the transport parameter match.
+	 * Sample case:     sips:host;transport=tcp
+	 * See https://trac.pjsip.org/repos/ticket/1319
+	 */
+	flag = pjsip_transport_get_flag_from_type(dest_info->type);
+	if ((flag & dest_info->flag) != dest_info->flag) {
+	    pjsip_transport_type_e t;
+
+	    t = pjsip_transport_get_type_from_flag(dest_info->flag);
+	    if (t != PJSIP_TRANSPORT_UNSPECIFIED)
+		dest_info->type = t;
+	}
+
+    } else if (PJSIP_URI_SCHEME_IS_SIP(target_uri)) {
+	pjsip_uri *uri = (pjsip_uri*) target_uri;
+	const pjsip_sip_uri *url=(const pjsip_sip_uri*)pjsip_uri_get_uri(uri);
+	if (url->maddr_param.slen)
+	    pj_strdup(pool, &dest_info->addr.host, &url->maddr_param);
+	else
+	    pj_strdup(pool, &dest_info->addr.host, &url->host);
+	dest_info->addr.port = url->port;
+	dest_info->type = 
+            pjsip_transport_get_type_from_name(&url->transport_param);
+	dest_info->flag = 
+	    pjsip_transport_get_flag_from_type(dest_info->type);
+    } else {
+	/* Should have never reached here; app should have configured route
+	 * set when sending to tel: URI
+        pj_assert(!"Unsupported URI scheme!");
+	 */
+	PJ_TODO(SUPPORT_REQUEST_ADDR_RESOLUTION_FOR_TEL_URI);
+	return PJSIP_ENOROUTESET;
+    }
+
+    /* Handle IPv6 (http://trac.pjsip.org/repos/ticket/861) */
+    if (dest_info->type != PJSIP_TRANSPORT_UNSPECIFIED && 
+	pj_strchr(&dest_info->addr.host, ':'))
+    {
+	dest_info->type = (pjsip_transport_type_e)
+			  ((int)dest_info->type | PJSIP_TRANSPORT_IPV6);
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Find which destination to be used to send the request message, based
+ * on the request URI and Route headers in the message. The procedure
+ * used here follows the guidelines on sending the request in RFC 3261
+ * chapter 8.1.2.
+ */
+PJ_DEF(pj_status_t) pjsip_get_request_dest(const pjsip_tx_data *tdata,
+					   pjsip_host_info *dest_info )
+{
+    const pjsip_uri *target_uri;
+    const pjsip_route_hdr *first_route_hdr;
+    
+    PJ_ASSERT_RETURN(tdata->msg->type == PJSIP_REQUEST_MSG, 
+		     PJSIP_ENOTREQUESTMSG);
+    PJ_ASSERT_RETURN(dest_info != NULL, PJ_EINVAL);
+
+    /* Get the first "Route" header from the message.
+     */
+    first_route_hdr = (const pjsip_route_hdr*) 
+    		      pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);
+    if (first_route_hdr) {
+	target_uri = first_route_hdr->name_addr.uri;
+    } else {
+	target_uri = tdata->msg->line.req.uri;
+    }
+
+    return get_dest_info(target_uri, (pj_pool_t*)tdata->pool, dest_info);
+}
+
+
+/*
+ * Process route-set found in the request and calculate
+ * the destination to be used to send the request message, based
+ * on the request URI and Route headers in the message. The procedure
+ * used here follows the guidelines on sending the request in RFC 3261
+ * chapter 8.1.2.
+ */
+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 = get_dest_info(target_uri, tdata->pool, dest_info);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* 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;  
+}
+
+
+/*
+ * Swap the request URI and strict route back to the original position
+ * before #pjsip_process_route_set() function is called. This function
+ * should only used internally by PJSIP client authentication module.
+ */
+PJ_DEF(void) pjsip_restore_strict_route_set(pjsip_tx_data *tdata)
+{
+    pjsip_route_hdr *first_route_hdr, *last_route_hdr;
+
+    /* Check if we have found strict route before */
+    if (tdata->saved_strict_route == NULL) {
+	/* This request doesn't contain strict route */
+	return;
+    }
+
+    /* Find the first "Route" headers from the message. */
+    first_route_hdr = (pjsip_route_hdr*)
+		      pjsip_msg_find_hdr(tdata->msg, PJSIP_H_ROUTE, NULL);
+
+    if (first_route_hdr == NULL) {
+	/* User has modified message route? We don't expect this! */
+	pj_assert(!"Message route was modified?");
+	tdata->saved_strict_route = NULL;
+	return;
+    }
+
+    /* Find last Route header */
+    last_route_hdr = first_route_hdr;
+    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;
+    }
+
+    /* Put the last Route header as request URI, delete last Route
+     * header, and insert the saved strict route as the first Route.
+     */
+    tdata->msg->line.req.uri = last_route_hdr->name_addr.uri;
+    pj_list_insert_before(first_route_hdr, tdata->saved_strict_route);
+    pj_list_erase(last_route_hdr);
+
+    /* Reset */
+    tdata->saved_strict_route = NULL;
+}
+
+
+/* Transport callback for sending stateless request. 
+ * This is one of the most bizzare function in pjsip, so
+ * good luck if you happen to debug this function!!
+ */
+static void stateless_send_transport_cb( void *token,
+					 pjsip_tx_data *tdata,
+					 pj_ssize_t sent )
+{
+    pjsip_send_state *stateless_data = (pjsip_send_state*) token;
+
+    PJ_UNUSED_ARG(tdata);
+    pj_assert(tdata == stateless_data->tdata);
+
+    for (;;) {
+	pj_status_t status;
+	pj_bool_t cont;
+
+	pj_sockaddr_t *cur_addr;
+	pjsip_transport_type_e cur_addr_type;
+	int cur_addr_len;
+
+	pjsip_via_hdr *via;
+
+	if (sent == -PJ_EPENDING) {
+	    /* This is the initial process.
+	     * When the process started, this function will be called by
+	     * stateless_send_resolver_callback() with sent argument set to
+	     * -PJ_EPENDING.
+	     */
+	    cont = PJ_TRUE;
+	} else {
+	    /* There are two conditions here:
+	     * (1) Message is sent (i.e. sent > 0),
+	     * (2) Failure (i.e. sent <= 0)
+	     */
+	    cont = (sent > 0) ? PJ_FALSE :
+		   (tdata->dest_info.cur_addr<tdata->dest_info.addr.count-1);
+	    if (stateless_data->app_cb) {
+		(*stateless_data->app_cb)(stateless_data, sent, &cont);
+	    } else {
+		/* Doesn't have application callback.
+		 * Terminate the process.
+		 */
+		cont = PJ_FALSE;
+	    }
+	}
+
+	/* Finished with this transport. */
+	if (stateless_data->cur_transport) {
+	    pjsip_transport_dec_ref(stateless_data->cur_transport);
+	    stateless_data->cur_transport = NULL;
+	}
+
+	/* Done if application doesn't want to continue. */
+	if (sent > 0 || !cont) {
+	    pjsip_tx_data_dec_ref(tdata);
+	    return;
+	}
+
+	/* Try next address, if any, and only when this is not the 
+	 * first invocation. 
+	 */
+	if (sent != -PJ_EPENDING) {
+	    tdata->dest_info.cur_addr++;
+	}
+
+	/* Have next address? */
+	if (tdata->dest_info.cur_addr >= tdata->dest_info.addr.count) {
+	    /* This only happens when a rather buggy application has
+	     * sent 'cont' to PJ_TRUE when the initial value was PJ_FALSE.
+	     * In this case just stop the processing; we don't need to
+	     * call the callback again as application has been informed
+	     * before.
+	     */
+	    pjsip_tx_data_dec_ref(tdata);
+	    return;
+	}
+
+	/* Keep current server address information handy. */
+	cur_addr = &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr;
+	cur_addr_type = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].type;
+	cur_addr_len = tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len;
+
+	/* Acquire transport. */
+	status = pjsip_endpt_acquire_transport2(stateless_data->endpt,
+						cur_addr_type,
+						cur_addr,
+						cur_addr_len,
+						&tdata->tp_sel,
+						tdata,
+						&stateless_data->cur_transport);
+	if (status != PJ_SUCCESS) {
+	    sent = -status;
+	    continue;
+	}
+
+	/* Modify Via header. */
+	via = (pjsip_via_hdr*) pjsip_msg_find_hdr( tdata->msg,
+						   PJSIP_H_VIA, NULL);
+	if (!via) {
+	    /* Shouldn't happen if request was created with PJSIP API! 
+	     * But we handle the case anyway for robustness.
+	     */
+	    pj_assert(!"Via header not found!");
+	    via = pjsip_via_hdr_create(tdata->pool);
+	    pjsip_msg_insert_first_hdr(tdata->msg, (pjsip_hdr*)via);
+	}
+
+	if (via->branch_param.slen == 0) {
+	    pj_str_t tmp;
+	    via->branch_param.ptr = (char*)pj_pool_alloc(tdata->pool,
+						  	 PJSIP_MAX_BRANCH_LEN);
+	    via->branch_param.slen = PJSIP_MAX_BRANCH_LEN;
+	    pj_memcpy(via->branch_param.ptr, PJSIP_RFC3261_BRANCH_ID,
+		      PJSIP_RFC3261_BRANCH_LEN);
+	    tmp.ptr = via->branch_param.ptr + PJSIP_RFC3261_BRANCH_LEN + 2;
+	    *(tmp.ptr-2) = 80; *(tmp.ptr-1) = 106;
+	    pj_generate_unique_string(&tmp);
+	}
+
+	via->transport = pj_str(stateless_data->cur_transport->type_name);
+        if (tdata->via_addr.host.slen > 0 &&
+            tdata->via_tp == (void *)stateless_data->cur_transport)
+        {
+            via->sent_by = tdata->via_addr;
+        } else {
+	    via->sent_by = stateless_data->cur_transport->local_name;
+        }
+	via->rport_param = pjsip_cfg()->endpt.disable_rport ? -1 : 0;
+
+	/* Add/remove "alias" param to/from Via header on connection 
+	 * oriented/less transport, if configured.
+	 */
+	if (pjsip_cfg()->endpt.req_has_via_alias &&
+	    tdata->msg->type == PJSIP_REQUEST_MSG)
+	{
+	    const pj_str_t ALIAS_STR = {"alias", 5};
+	    pjsip_param *alias_param;
+	    pj_bool_t is_datagram;
+
+	    alias_param = pjsip_param_find(&via->other_param, &ALIAS_STR);
+	    is_datagram = (stateless_data->cur_transport->flag & 
+			   PJSIP_TRANSPORT_DATAGRAM);
+	    if (!is_datagram && !alias_param) {
+		alias_param = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_param);
+		alias_param->name = ALIAS_STR;
+		pj_list_push_back(&via->other_param, alias_param);
+	    } else if (is_datagram && alias_param) {
+		pj_list_erase(alias_param);
+	    }
+	}
+
+	pjsip_tx_data_invalidate_msg(tdata);
+
+	/* Send message using this transport. */
+	status = pjsip_transport_send( stateless_data->cur_transport,
+				       tdata,
+				       cur_addr,
+				       cur_addr_len,
+				       stateless_data,
+				       &stateless_send_transport_cb);
+	if (status == PJ_SUCCESS) {
+	    /* Recursively call this function. */
+	    sent = tdata->buf.cur - tdata->buf.start;
+	    stateless_send_transport_cb( stateless_data, tdata, sent );
+	    return;
+	} else if (status == PJ_EPENDING) {
+	    /* This callback will be called later. */
+	    return;
+	} else {
+	    /* Recursively call this function. */
+	    sent = -status;
+	    stateless_send_transport_cb( stateless_data, tdata, sent );
+	    return;
+	}
+    }
+
+}
+
+/* Resolver callback for sending stateless request. */
+static void 
+stateless_send_resolver_callback( pj_status_t status,
+				  void *token,
+				  const struct pjsip_server_addresses *addr)
+{
+    pjsip_send_state *stateless_data = (pjsip_send_state*) token;
+    pjsip_tx_data *tdata = stateless_data->tdata;
+
+    /* Fail on server resolution. */
+    if (status != PJ_SUCCESS) {
+	if (stateless_data->app_cb) {
+	    pj_bool_t cont = PJ_FALSE;
+	    (*stateless_data->app_cb)(stateless_data, -status, &cont);
+	}
+	pjsip_tx_data_dec_ref(tdata);
+	return;
+    }
+
+    /* Copy server addresses */
+    if (addr && addr != &tdata->dest_info.addr) {
+	pj_memcpy( &tdata->dest_info.addr, addr, 
+	           sizeof(pjsip_server_addresses));
+    }
+    pj_assert(tdata->dest_info.addr.count != 0);
+
+    /* RFC 3261 section 18.1.1:
+     * If a request is within 200 bytes of the path MTU, or if it is larger
+     * than 1300 bytes and the path MTU is unknown, the request MUST be sent
+     * using an RFC 2914 [43] congestion controlled transport protocol, such
+     * as TCP.
+     */
+    if (pjsip_cfg()->endpt.disable_tcp_switch==0 &&
+	tdata->msg->type == PJSIP_REQUEST_MSG &&
+	tdata->dest_info.addr.count > 0 && 
+	tdata->dest_info.addr.entry[0].type == PJSIP_TRANSPORT_UDP)
+    {
+	int len;
+
+	/* Encode the request */
+	status = pjsip_tx_data_encode(tdata);
+	if (status != PJ_SUCCESS) {
+	    if (stateless_data->app_cb) {
+		pj_bool_t cont = PJ_FALSE;
+		(*stateless_data->app_cb)(stateless_data, -status, &cont);
+	    }
+	    pjsip_tx_data_dec_ref(tdata);
+	    return;
+	}
+
+	/* Check if request message is larger than 1300 bytes. */
+	len = (int)(tdata->buf.cur - tdata->buf.start);
+	if (len >= PJSIP_UDP_SIZE_THRESHOLD) {
+	    int i;
+	    int count = tdata->dest_info.addr.count;
+
+	    PJ_LOG(5,(THIS_FILE, "%s exceeds UDP size threshold (%u), "
+				 "sending with TCP",
+				 pjsip_tx_data_get_info(tdata),
+				 PJSIP_UDP_SIZE_THRESHOLD));
+
+	    /* Insert "TCP version" of resolved UDP addresses at the
+	     * beginning.
+	     */
+	    if (count * 2 > PJSIP_MAX_RESOLVED_ADDRESSES)
+		count = PJSIP_MAX_RESOLVED_ADDRESSES / 2;
+	    for (i = 0; i < count; ++i) {
+		pj_memcpy(&tdata->dest_info.addr.entry[i+count],
+			  &tdata->dest_info.addr.entry[i],
+			  sizeof(tdata->dest_info.addr.entry[0]));
+		tdata->dest_info.addr.entry[i].type = PJSIP_TRANSPORT_TCP;
+	    }
+	    tdata->dest_info.addr.count = count * 2;
+	}
+    }
+
+    /* Process the addresses. */
+    stateless_send_transport_cb( stateless_data, tdata, -PJ_EPENDING);
+}
+
+/*
+ * Send stateless request.
+ * The sending process consists of several stages:
+ *  - determine which host to contact (#pjsip_get_request_addr).
+ *  - resolve the host (#pjsip_endpt_resolve)
+ *  - establish transport (#pjsip_endpt_acquire_transport)
+ *  - send the message (#pjsip_transport_send)
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_send_request_stateless(pjsip_endpoint *endpt, 
+				   pjsip_tx_data *tdata,
+				   void *token,
+				   pjsip_send_callback cb)
+{
+    pjsip_host_info dest_info;
+    pjsip_send_state *stateless_data;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(endpt && tdata, PJ_EINVAL);
+
+    /* Get destination name to contact. */
+    status = pjsip_process_route_set(tdata, &dest_info);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Keep stateless data. */
+    stateless_data = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_send_state);
+    stateless_data->token = token;
+    stateless_data->endpt = endpt;
+    stateless_data->tdata = tdata;
+    stateless_data->app_cb = cb;
+
+    /* If destination info has not been initialized (this applies for most
+     * all requests except CANCEL), resolve destination host. The processing
+     * then resumed when the resolving callback is called. For CANCEL, the
+     * destination info must have been copied from the original INVITE so
+     * proceed to sending the request directly.
+     */
+    if (tdata->dest_info.addr.count == 0) {
+	/* Copy the destination host name to TX data */
+	pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host);
+
+	pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, stateless_data,
+			     &stateless_send_resolver_callback);
+    } else {
+	PJ_LOG(5,(THIS_FILE, "%s: skipping target resolution because "
+	                     "address is already set",
+			     pjsip_tx_data_get_info(tdata)));
+	stateless_send_resolver_callback(PJ_SUCCESS, stateless_data,
+					 &tdata->dest_info.addr);
+    }
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Send raw data to a destination.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_send_raw( pjsip_endpoint *endpt,
+					  pjsip_transport_type_e tp_type,
+					  const pjsip_tpselector *sel,
+					  const void *raw_data,
+					  pj_size_t data_len,
+					  const pj_sockaddr_t *addr,
+					  int addr_len,
+					  void *token,
+					  pjsip_tp_send_callback cb)
+{
+    return pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(endpt), tp_type, sel,
+				NULL, raw_data, data_len, addr, addr_len,
+				token, cb);
+}
+
+
+/* Callback data for sending raw data */
+struct send_raw_data
+{
+    pjsip_endpoint	    *endpt;
+    pjsip_tx_data	    *tdata;
+    pjsip_tpselector	    *sel;
+    void		    *app_token;
+    pjsip_tp_send_callback   app_cb;
+};
+
+
+/* Resolver callback for sending raw data. */
+static void send_raw_resolver_callback( pj_status_t status,
+    					void *token,
+					const pjsip_server_addresses *addr)
+{
+    struct send_raw_data *sraw_data = (struct send_raw_data*) token;
+
+    if (status != PJ_SUCCESS) {
+	if (sraw_data->app_cb) {
+	    (*sraw_data->app_cb)(sraw_data->app_token, sraw_data->tdata,
+				 -status);
+	}
+    } else {
+	pj_size_t data_len;
+
+	pj_assert(addr->count != 0);
+
+	/* Avoid tdata destroyed by pjsip_tpmgr_send_raw(). */
+	pjsip_tx_data_add_ref(sraw_data->tdata);
+
+	data_len = sraw_data->tdata->buf.cur - sraw_data->tdata->buf.start;
+	status = pjsip_tpmgr_send_raw(pjsip_endpt_get_tpmgr(sraw_data->endpt),
+				      addr->entry[0].type,
+				      sraw_data->sel, sraw_data->tdata,
+				      sraw_data->tdata->buf.start, data_len,
+				      &addr->entry[0].addr, 
+				      addr->entry[0].addr_len, 
+				      sraw_data->app_token,
+				      sraw_data->app_cb);
+	if (status == PJ_SUCCESS) {
+	    (*sraw_data->app_cb)(sraw_data->app_token, sraw_data->tdata,
+				 data_len);
+	} else if (status != PJ_EPENDING) {
+	    (*sraw_data->app_cb)(sraw_data->app_token, sraw_data->tdata,
+				 -status);
+	}
+    }
+
+    if (sraw_data->sel) {
+	pjsip_tpselector_dec_ref(sraw_data->sel);
+    }
+    pjsip_tx_data_dec_ref(sraw_data->tdata);
+}
+
+
+/*
+ * Send raw data to the specified destination URI. 
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_send_raw_to_uri(pjsip_endpoint *endpt,
+						const pj_str_t *p_dst_uri,
+						const pjsip_tpselector *sel,
+						const void *raw_data,
+						pj_size_t data_len,
+						void *token,
+						pjsip_tp_send_callback cb)
+{
+    pjsip_tx_data *tdata;
+    struct send_raw_data *sraw_data;
+    pj_str_t dst_uri;
+    pjsip_uri *uri;
+    pjsip_host_info dest_info;
+    pj_status_t status;
+
+    /* Allocate buffer */
+    status = pjsip_endpt_create_tdata(endpt, &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    pjsip_tx_data_add_ref(tdata);
+
+    /* Duplicate URI since parser requires URI to be NULL terminated */
+    pj_strdup_with_null(tdata->pool, &dst_uri, p_dst_uri);
+
+    /* Parse URI */
+    uri = pjsip_parse_uri(tdata->pool, dst_uri.ptr, dst_uri.slen, 0);
+    if (uri == NULL) {
+	pjsip_tx_data_dec_ref(tdata);
+	return PJSIP_EINVALIDURI;
+    }
+
+    /* Build destination info. */
+    status = get_dest_info(uri, tdata->pool, &dest_info);
+    if (status != PJ_SUCCESS) {
+	pjsip_tx_data_dec_ref(tdata);
+	return status;
+    }
+
+    /* Copy data (note: data_len may be zero!) */
+    tdata->buf.start = (char*) pj_pool_alloc(tdata->pool, data_len+1);
+    tdata->buf.end = tdata->buf.start + data_len + 1;
+    if (data_len)
+	pj_memcpy(tdata->buf.start, raw_data, data_len);
+    tdata->buf.cur = tdata->buf.start + data_len;
+
+    /* Init send_raw_data */
+    sraw_data = PJ_POOL_ZALLOC_T(tdata->pool, struct send_raw_data);
+    sraw_data->endpt = endpt;
+    sraw_data->tdata = tdata;
+    sraw_data->app_token = token;
+    sraw_data->app_cb = cb;
+
+    if (sel) {
+	sraw_data->sel = PJ_POOL_ALLOC_T(tdata->pool, pjsip_tpselector);
+	pj_memcpy(sraw_data->sel, sel, sizeof(pjsip_tpselector));
+	pjsip_tpselector_add_ref(sraw_data->sel);
+    }
+
+    /* Copy the destination host name to TX data */
+    pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host);
+
+    /* Resolve destination host.
+     * The processing then resumed when the resolving callback is called.
+     */
+    pjsip_endpt_resolve( endpt, tdata->pool, &dest_info, sraw_data,
+			 &send_raw_resolver_callback);
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Determine which address (and transport) to use to send response message
+ * based on the received request. This function follows the specification
+ * in section 18.2.2 of RFC 3261 and RFC 3581 for calculating the destination
+ * address and transport.
+ */
+PJ_DEF(pj_status_t) pjsip_get_response_addr( pj_pool_t *pool,
+					     pjsip_rx_data *rdata,
+					     pjsip_response_addr *res_addr )
+{
+    pjsip_transport *src_transport = rdata->tp_info.transport;
+
+    /* Check arguments. */
+    PJ_ASSERT_RETURN(pool && rdata && res_addr, PJ_EINVAL);
+
+    /* rdata must be a request message! */
+    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
+		     PJ_EINVAL);
+
+    /* All requests must have "received" parameter.
+     * This must always be done in transport layer.
+     */
+    pj_assert(rdata->msg_info.via->recvd_param.slen != 0);
+
+    /* Do the calculation based on RFC 3261 Section 18.2.2 and RFC 3581 */
+
+    if (PJSIP_TRANSPORT_IS_RELIABLE(src_transport)) {
+	/* For reliable protocol such as TCP or SCTP, or TLS over those, the
+	 * response MUST be sent using the existing connection to the source
+	 * of the original request that created the transaction, if that 
+	 * connection is still open. 
+	 * If that connection is no longer open, the server SHOULD open a 
+	 * connection to the IP address in the received parameter, if present,
+	 * using the port in the sent-by value, or the default port for that 
+	 * transport, if no port is specified. 
+	 * If that connection attempt fails, the server SHOULD use the 
+	 * procedures in [4] for servers in order to determine the IP address
+	 * and port to open the connection and send the response to.
+	 */
+	res_addr->transport = rdata->tp_info.transport;
+	pj_memcpy(&res_addr->addr, &rdata->pkt_info.src_addr,
+		  rdata->pkt_info.src_addr_len);
+	res_addr->addr_len = rdata->pkt_info.src_addr_len;
+	res_addr->dst_host.type=(pjsip_transport_type_e)src_transport->key.type;
+	res_addr->dst_host.flag = src_transport->flag;
+	pj_strdup( pool, &res_addr->dst_host.addr.host, 
+		   &rdata->msg_info.via->recvd_param);
+	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
+	if (res_addr->dst_host.addr.port == 0) {
+	    res_addr->dst_host.addr.port = 
+		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
+	}
+
+    } else if (rdata->msg_info.via->maddr_param.slen) {
+	/* Otherwise, if the Via header field value contains a maddr parameter,
+	 * the response MUST be forwarded to the address listed there, using 
+	 * the port indicated in sent-by, or port 5060 if none is present. 
+	 * If the address is a multicast address, the response SHOULD be sent 
+	 * using the TTL indicated in the ttl parameter, or with a TTL of 1 if
+	 * that parameter is not present. 
+	 */
+	res_addr->transport = NULL;
+	res_addr->dst_host.type=(pjsip_transport_type_e)src_transport->key.type;
+	res_addr->dst_host.flag = src_transport->flag;
+	pj_strdup( pool, &res_addr->dst_host.addr.host, 
+		   &rdata->msg_info.via->maddr_param);
+	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
+	if (res_addr->dst_host.addr.port == 0)
+	    res_addr->dst_host.addr.port = 5060;
+
+    } else if (rdata->msg_info.via->rport_param >= 0) {
+	/* There is both a "received" parameter and an "rport" parameter, 
+	 * the response MUST be sent to the IP address listed in the "received"
+	 * parameter, and the port in the "rport" parameter. 
+	 * The response MUST be sent from the same address and port that the 
+	 * corresponding request was received on.
+	 */
+	res_addr->transport = rdata->tp_info.transport;
+	pj_memcpy(&res_addr->addr, &rdata->pkt_info.src_addr,
+		  rdata->pkt_info.src_addr_len);
+	res_addr->addr_len = rdata->pkt_info.src_addr_len;
+	res_addr->dst_host.type=(pjsip_transport_type_e)src_transport->key.type;
+	res_addr->dst_host.flag = src_transport->flag;
+	pj_strdup( pool, &res_addr->dst_host.addr.host, 
+		   &rdata->msg_info.via->recvd_param);
+	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
+	if (res_addr->dst_host.addr.port == 0) {
+	    res_addr->dst_host.addr.port = 
+		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
+	}
+
+    } else {
+	res_addr->transport = NULL;
+	res_addr->dst_host.type=(pjsip_transport_type_e)src_transport->key.type;
+	res_addr->dst_host.flag = src_transport->flag;
+	pj_strdup( pool, &res_addr->dst_host.addr.host, 
+		   &rdata->msg_info.via->recvd_param);
+	res_addr->dst_host.addr.port = rdata->msg_info.via->sent_by.port;
+	if (res_addr->dst_host.addr.port == 0) {
+	    res_addr->dst_host.addr.port = 
+		pjsip_transport_get_default_port_for_type(res_addr->dst_host.type);
+	}
+    }
+
+    return PJ_SUCCESS;
+}
+
+/*
+ * Callback called by transport during send_response.
+ */
+static void send_response_transport_cb(void *token, pjsip_tx_data *tdata,
+				       pj_ssize_t sent)
+{
+    pjsip_send_state *send_state = (pjsip_send_state*) token;
+    pj_bool_t cont = PJ_FALSE;
+
+    /* Call callback, if any. */
+    if (send_state->app_cb)
+	(*send_state->app_cb)(send_state, sent, &cont);
+
+    /* Decrement transport reference counter. */
+    pjsip_transport_dec_ref(send_state->cur_transport);
+
+    /* Decrement transmit data ref counter. */
+    pjsip_tx_data_dec_ref(tdata);
+}
+
+/*
+ * Resolver calback during send_response.
+ */
+static void send_response_resolver_cb( pj_status_t status, void *token,
+				       const pjsip_server_addresses *addr )
+{
+    pjsip_send_state *send_state = (pjsip_send_state*) token;
+
+    if (status != PJ_SUCCESS) {
+	if (send_state->app_cb) {
+	    pj_bool_t cont = PJ_FALSE;
+	    (*send_state->app_cb)(send_state, -status, &cont);
+	}
+	pjsip_tx_data_dec_ref(send_state->tdata);
+	return;
+    }
+
+    /* Only handle the first address resolved. */
+
+    /* Acquire transport. */
+    status = pjsip_endpt_acquire_transport2(send_state->endpt, 
+					    addr->entry[0].type,
+					    &addr->entry[0].addr,
+					    addr->entry[0].addr_len,
+					    &send_state->tdata->tp_sel,
+					    send_state->tdata,
+					    &send_state->cur_transport);
+    if (status != PJ_SUCCESS) {
+	if (send_state->app_cb) {
+	    pj_bool_t cont = PJ_FALSE;
+	    (*send_state->app_cb)(send_state, -status, &cont);
+	}
+	pjsip_tx_data_dec_ref(send_state->tdata);
+	return;
+    }
+
+    /* Update address in send_state. */
+    pj_memcpy(&send_state->tdata->dest_info.addr, addr, sizeof(*addr));
+
+    /* Send response using the transoprt. */
+    status = pjsip_transport_send( send_state->cur_transport, 
+				   send_state->tdata,
+				   &addr->entry[0].addr,
+				   addr->entry[0].addr_len,
+				   send_state,
+				   &send_response_transport_cb);
+    if (status == PJ_SUCCESS) {
+	pj_ssize_t sent = send_state->tdata->buf.cur - 
+			  send_state->tdata->buf.start;
+	send_response_transport_cb(send_state, send_state->tdata, sent);
+
+    } else if (status == PJ_EPENDING) {
+	/* Transport callback will be called later. */
+    } else {
+	send_response_transport_cb(send_state, send_state->tdata, -status);
+    }
+}
+
+/*
+ * Send response.
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_send_response( pjsip_endpoint *endpt,
+					       pjsip_response_addr *res_addr,
+					       pjsip_tx_data *tdata,
+					       void *token,
+					       pjsip_send_callback cb)
+{
+    /* Determine which transports and addresses to send the response,
+     * based on Section 18.2.2 of RFC 3261.
+     */
+    pjsip_send_state *send_state;
+    pj_status_t status;
+
+    /* Create structure to keep the sending state. */
+    send_state = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_send_state);
+    send_state->endpt = endpt;
+    send_state->tdata = tdata;
+    send_state->token = token;
+    send_state->app_cb = cb;
+
+    if (res_addr->transport != NULL) {
+	send_state->cur_transport = res_addr->transport;
+	pjsip_transport_add_ref(send_state->cur_transport);
+
+	status = pjsip_transport_send( send_state->cur_transport, tdata, 
+				       &res_addr->addr,
+				       res_addr->addr_len,
+				       send_state,
+				       &send_response_transport_cb );
+	if (status == PJ_SUCCESS) {
+	    pj_ssize_t sent = tdata->buf.cur - tdata->buf.start;
+	    send_response_transport_cb(send_state, tdata, sent);
+	    return PJ_SUCCESS;
+	} else if (status == PJ_EPENDING) {
+	    /* Callback will be called later. */
+	    return PJ_SUCCESS;
+	} else {
+	    pjsip_transport_dec_ref(send_state->cur_transport);
+	    return status;
+	}
+    } else {
+	/* Copy the destination host name to TX data */
+	pj_strdup(tdata->pool, &tdata->dest_info.name, 
+		  &res_addr->dst_host.addr.host);
+
+	pjsip_endpt_resolve(endpt, tdata->pool, &res_addr->dst_host, 
+			    send_state, &send_response_resolver_cb);
+	return PJ_SUCCESS;
+    }
+}
+
+/*
+ * Send response combo
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_send_response2( pjsip_endpoint *endpt,
+					        pjsip_rx_data *rdata,
+					        pjsip_tx_data *tdata,
+						void *token,
+						pjsip_send_callback cb)
+{
+    pjsip_response_addr res_addr;
+    pj_status_t status;
+
+    status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
+    if (status != PJ_SUCCESS) {
+	pjsip_tx_data_dec_ref(tdata);
+	return PJ_SUCCESS;
+    }
+
+    status = pjsip_endpt_send_response(endpt, &res_addr, tdata, token, cb);
+    return status;
+}
+
+
+/*
+ * Send response
+ */
+PJ_DEF(pj_status_t) pjsip_endpt_respond_stateless( pjsip_endpoint *endpt,
+						   pjsip_rx_data *rdata,
+						   int st_code,
+						   const pj_str_t *st_text,
+						   const pjsip_hdr *hdr_list,
+						   const pjsip_msg_body *body)
+{
+    pj_status_t status;
+    pjsip_response_addr res_addr;
+    pjsip_tx_data *tdata;
+
+    /* Verify arguments. */
+    PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL);
+    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
+		     PJSIP_ENOTREQUESTMSG);
+
+    /* Check that no UAS transaction has been created for this request. 
+     * If UAS transaction has been created for this request, application
+     * MUST send the response statefully using that transaction.
+     */
+    PJ_ASSERT_RETURN(pjsip_rdata_get_tsx(rdata)==NULL, PJ_EINVALIDOP);
+
+    /* Create response message */
+    status = pjsip_endpt_create_response( endpt, rdata, st_code, st_text, 
+					  &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Add the message headers, if any */
+    if (hdr_list) {
+	const pjsip_hdr *hdr = hdr_list->next;
+	while (hdr != hdr_list) {
+	    pjsip_msg_add_hdr(tdata->msg, 
+	    		      (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr) );
+	    hdr = hdr->next;
+	}
+    }
+
+    /* Add the message body, if any. */
+    if (body) {
+	tdata->msg->body = pjsip_msg_body_clone( tdata->pool, body );
+	if (tdata->msg->body == NULL) {
+	    pjsip_tx_data_dec_ref(tdata);
+	    return status;
+	}
+    }
+
+    /* Get where to send request. */
+    status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr );
+    if (status != PJ_SUCCESS) {
+	pjsip_tx_data_dec_ref(tdata);
+	return status;
+    }
+
+    /* Send! */
+    status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL );
+    if (status != PJ_SUCCESS) {
+	pjsip_tx_data_dec_ref(tdata);
+	return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Get the event string from the event ID.
+ */
+PJ_DEF(const char *) pjsip_event_str(pjsip_event_id_e e)
+{
+    return event_str[e];
+}
+
diff --git a/jni/pjproject-android/.svn/pristine/f5/f550cc05ae813e040eeac313a71f6f8d6aef441f.svn-base b/jni/pjproject-android/.svn/pristine/f5/f550cc05ae813e040eeac313a71f6f8d6aef441f.svn-base
new file mode 100644
index 0000000..0475bac
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f550cc05ae813e040eeac313a71f6f8d6aef441f.svn-base
@@ -0,0 +1,65 @@
+

+                           PJSUA TEST FRAMEWORK

+                        =========================

+

+0. What is this

+---------------

+This is the automated testing scripts for pjsua. It can do many things (just 

+don't ask it to write good documentation :) ).

+

+

+1. Requirements

+---------------

+To run the tests you need:

+ - Python (tested with Python 2.5.2)

+ - pjsua application, built and placed in pjsip-apps/bin directory

+ - the pjsua must be built with:

+     - SRTP enabled (the default)

+

+

+2. Using

+--------

+To run all the tests:

+  $ python [OPTIONS] runall.py

+

+To run individual test:

+  $ python [OPTIONS] run.py MODULE CONFIG

+

+Where options:

+  -e EXE	use EXE as pjsua executable

+  -n		use null audio

+  -r TEST	(for runall.py only) resume test at TEST

+

+  

+For each individual tests, the run.py is the main entry for the test. It 

+imports the various inc_xxx.py files, and it will load the MODULE. The MODULE 

+contains specific test flows, and we have few of them:

+

+  - mod_run.py: 

+  	a simple test which just run pjsua with the configuration from CONFIG 

+	file and checks if pjsua can start properly.

+

+  - mod_call.py: 

+  	call testing where it spawns two pjsua instances each with configura-

+	tions as specified in CONFIG file, makes one pjsua call the other, and 

+	checks if the call can be established.

+

+  - mod_pres.py:

+  	presence testing

+

+  - mod_sendto.py:

+  	Simple UAC to send arbitrary SIP message to pjsua. Good to test

+	various incoming INVITE scenarios

+

+  - mod_media_playrec.py:

+  	Mainly for resampling quality testing

+

+  - mod_pesq.py

+  	Measure call quality of various call settings with PESQ, for people 

+	who have PESQ tool and license

+

+Example:

+  $ python run.py mod_run.py scripts-run/100_simple.py

+  $ python run.py mod_call.py scripts-call/100_simple.py

+

+

diff --git a/jni/pjproject-android/.svn/pristine/f5/f55cc43a147ef524bd7529d7ad6ac4e54fa312b5.svn-base b/jni/pjproject-android/.svn/pristine/f5/f55cc43a147ef524bd7529d7ad6ac4e54fa312b5.svn-base
new file mode 100644
index 0000000..2107ac0
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f55cc43a147ef524bd7529d7ad6ac4e54fa312b5.svn-base
@@ -0,0 +1,24 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2009-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+
+/*
+ * This file is a C++ wrapper, see ticket #886 for details.
+ */
+
+#include "exception.c"
diff --git a/jni/pjproject-android/.svn/pristine/f5/f5a338ccf525bd84b44afbd4e1ce1ae67cc720c4.svn-base b/jni/pjproject-android/.svn/pristine/f5/f5a338ccf525bd84b44afbd4e1ce1ae67cc720c4.svn-base
new file mode 100644
index 0000000..de59b82
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f5a338ccf525bd84b44afbd4e1ce1ae67cc720c4.svn-base
@@ -0,0 +1,7 @@
+# $Id$
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, const.STATE_EARLY, "h"]]
diff --git a/jni/pjproject-android/.svn/pristine/f5/f5e9bc291b01d9089d7de50a258d0d31984e5272.svn-base b/jni/pjproject-android/.svn/pristine/f5/f5e9bc291b01d9089d7de50a258d0d31984e5272.svn-base
new file mode 100644
index 0000000..566bf31
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f5e9bc291b01d9089d7de50a258d0d31984e5272.svn-base
@@ -0,0 +1,20 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "sdl_dev.c"
diff --git a/jni/pjproject-android/.svn/pristine/f5/f5fdc73b4c7c7a1e1fdd3bfafaa7be35eedadf9c.svn-base b/jni/pjproject-android/.svn/pristine/f5/f5fdc73b4c7c7a1e1fdd3bfafaa7be35eedadf9c.svn-base
new file mode 100644
index 0000000..70c8c1f
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/f5/f5fdc73b4c7c7a1e1fdd3bfafaa7be35eedadf9c.svn-base
@@ -0,0 +1,47 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */
+#include <pj/os.h>
+#include <pj/errno.h>
+#include <pj/compat/time.h>
+
+#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H!=0
+#    include <unistd.h>
+#endif
+
+#include <errno.h>
+
+///////////////////////////////////////////////////////////////////////////////
+
+PJ_DEF(pj_status_t) pj_gettimeofday(pj_time_val *p_tv)
+{
+    struct timeval the_time;
+    int rc;
+
+    PJ_CHECK_STACK();
+
+    rc = gettimeofday(&the_time, NULL);
+    if (rc != 0)
+	return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
+
+    p_tv->sec = the_time.tv_sec;
+    p_tv->msec = the_time.tv_usec / 1000;
+    return PJ_SUCCESS;
+}
+