* #27232: jni: added pjproject checkout as regular git content

We will remove it once the next release of pjsip (with Android support)
comes out and is merged into SFLphone.
diff --git a/jni/pjproject-android/.svn/pristine/bf/bfcca63328e4698589105fd447e1396d7b255ae7.svn-base b/jni/pjproject-android/.svn/pristine/bf/bfcca63328e4698589105fd447e1396d7b255ae7.svn-base
new file mode 100644
index 0000000..f53243d
--- /dev/null
+++ b/jni/pjproject-android/.svn/pristine/bf/bfcca63328e4698589105fd447e1396d7b255ae7.svn-base
@@ -0,0 +1,700 @@
+/* $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 "turn.h"
+#include "auth.h"
+
+#define MAX_CLIENTS		32
+#define MAX_PEERS_PER_CLIENT	8
+//#define MAX_HANDLES		(MAX_CLIENTS*MAX_PEERS_PER_CLIENT+MAX_LISTENERS)
+#define MAX_HANDLES		PJ_IOQUEUE_MAX_HANDLES
+#define MAX_TIMER		(MAX_HANDLES * 2)
+#define MIN_PORT		49152
+#define MAX_PORT		65535
+#define MAX_LISTENERS		16
+#define MAX_THREADS		2
+#define MAX_NET_EVENTS		1000
+
+/* Prototypes */
+static int server_thread_proc(void *arg);
+static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
+				   void *token,
+				   const void *pkt,
+				   pj_size_t pkt_size,
+				   const pj_sockaddr_t *dst_addr,
+				   unsigned addr_len);
+static pj_status_t on_rx_stun_request(pj_stun_session *sess,
+				      const pj_uint8_t *pkt,
+				      unsigned pkt_len,
+				      const pj_stun_rx_data *rdata,
+				      void *user_data,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len);
+
+struct saved_cred
+{
+    pj_str_t realm;
+    pj_str_t username;
+    pj_str_t nonce;
+    int	     data_type;
+    pj_str_t data;
+};
+
+
+/*
+ * Get transport type name, normally for logging purpose only.
+ */
+PJ_DEF(const char*) pj_turn_tp_type_name(int tp_type)
+{
+    /* Must be 3 characters long! */
+    if (tp_type == PJ_TURN_TP_UDP) {
+	return "UDP";
+    } else if (tp_type == PJ_TURN_TP_TCP) {
+	return "TCP";
+    } else {
+	pj_assert(!"Unsupported transport");
+	return "???";
+    }
+}
+
+/*
+ * Create server.
+ */
+PJ_DEF(pj_status_t) pj_turn_srv_create(pj_pool_factory *pf, 
+				       pj_turn_srv **p_srv)
+{
+    pj_pool_t *pool;
+    pj_stun_session_cb sess_cb;
+    pj_turn_srv *srv;
+    unsigned i;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(pf && p_srv, PJ_EINVAL);
+
+    /* Create server and init core settings */
+    pool = pj_pool_create(pf, "srv%p", 1000, 1000, NULL);
+    srv = PJ_POOL_ZALLOC_T(pool, pj_turn_srv);
+    srv->obj_name = pool->obj_name;
+    srv->core.pf = pf;
+    srv->core.pool = pool;
+    srv->core.tls_key = srv->core.tls_data = -1;
+    
+    /* Create ioqueue */
+    status = pj_ioqueue_create(pool, MAX_HANDLES, &srv->core.ioqueue);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Server mutex */
+    status = pj_lock_create_recursive_mutex(pool, srv->obj_name, 
+					    &srv->core.lock);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Allocate TLS */
+    status = pj_thread_local_alloc(&srv->core.tls_key);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    status = pj_thread_local_alloc(&srv->core.tls_data);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+    
+    /* Create timer heap */
+    status = pj_timer_heap_create(pool, MAX_TIMER, &srv->core.timer_heap);
+    if (status != PJ_SUCCESS)
+	goto on_error;
+
+    /* Configure lock for the timer heap */
+    pj_timer_heap_set_lock(srv->core.timer_heap, srv->core.lock, PJ_FALSE);
+
+    /* Array of listeners */
+    srv->core.listener = (pj_turn_listener**)
+			 pj_pool_calloc(pool, MAX_LISTENERS, 
+					sizeof(srv->core.listener[0]));
+
+    /* Create hash tables */
+    srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
+    srv->tables.res = pj_hash_create(pool, MAX_CLIENTS);
+
+    /* Init ports settings */
+    srv->ports.min_udp = srv->ports.next_udp = MIN_PORT;
+    srv->ports.max_udp = MAX_PORT;
+    srv->ports.min_tcp = srv->ports.next_tcp = MIN_PORT;
+    srv->ports.max_tcp = MAX_PORT;
+
+    /* Init STUN config */
+    pj_stun_config_init(&srv->core.stun_cfg, pf, 0, srv->core.ioqueue,
+		        srv->core.timer_heap);
+
+    /* Init STUN credential */
+    srv->core.cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
+    srv->core.cred.data.dyn_cred.user_data = srv;
+    srv->core.cred.data.dyn_cred.get_auth = &pj_turn_get_auth;
+    srv->core.cred.data.dyn_cred.get_password = &pj_turn_get_password;
+    srv->core.cred.data.dyn_cred.verify_nonce = &pj_turn_verify_nonce;
+
+    /* Create STUN session to handle new allocation */
+    pj_bzero(&sess_cb, sizeof(sess_cb));
+    sess_cb.on_rx_request = &on_rx_stun_request;
+    sess_cb.on_send_msg = &on_tx_stun_msg;
+
+    status = pj_stun_session_create(&srv->core.stun_cfg, srv->obj_name,
+				    &sess_cb, PJ_FALSE, NULL,
+				    &srv->core.stun_sess);
+    if (status != PJ_SUCCESS) {
+	goto on_error;
+    }
+
+    pj_stun_session_set_user_data(srv->core.stun_sess, srv);
+    pj_stun_session_set_credential(srv->core.stun_sess, PJ_STUN_AUTH_LONG_TERM,
+				   &srv->core.cred);
+
+
+    /* Array of worker threads */
+    srv->core.thread_cnt = MAX_THREADS;
+    srv->core.thread = (pj_thread_t**)
+		       pj_pool_calloc(pool, srv->core.thread_cnt, 
+				      sizeof(pj_thread_t*));
+
+    /* Start the worker threads */
+    for (i=0; i<srv->core.thread_cnt; ++i) {
+	status = pj_thread_create(pool, srv->obj_name, &server_thread_proc, 
+				  srv, 0, 0, &srv->core.thread[i]);
+	if (status != PJ_SUCCESS)
+	    goto on_error;
+    }
+
+    /* We're done. Application should add listeners now */
+    PJ_LOG(4,(srv->obj_name, "TURN server v%s is running", 
+	      pj_get_version()));
+
+    *p_srv = srv;
+    return PJ_SUCCESS;
+
+on_error:
+    pj_turn_srv_destroy(srv);
+    return status;
+}
+
+
+/* 
+ * Handle timer and network events 
+ */
+static void srv_handle_events(pj_turn_srv *srv, const pj_time_val *max_timeout)
+{
+    /* timeout is 'out' var. This just to make compiler happy. */
+    pj_time_val timeout = { 0, 0};
+    unsigned net_event_count = 0;
+    int c;
+
+    /* Poll the timer. The timer heap has its own mutex for better 
+     * granularity, so we don't need to lock the server. 
+     */
+    timeout.sec = timeout.msec = 0;
+    c = pj_timer_heap_poll( srv->core.timer_heap, &timeout );
+
+    /* timer_heap_poll should never ever returns negative value, or otherwise
+     * ioqueue_poll() will block forever!
+     */
+    pj_assert(timeout.sec >= 0 && timeout.msec >= 0);
+    if (timeout.msec >= 1000) timeout.msec = 999;
+
+    /* If caller specifies maximum time to wait, then compare the value with
+     * the timeout to wait from timer, and use the minimum value.
+     */
+    if (max_timeout && PJ_TIME_VAL_GT(timeout, *max_timeout)) {
+	timeout = *max_timeout;
+    }
+
+    /* Poll ioqueue. 
+     * Repeat polling the ioqueue while we have immediate events, because
+     * timer heap may process more than one events, so if we only process
+     * one network events at a time (such as when IOCP backend is used),
+     * the ioqueue may have trouble keeping up with the request rate.
+     *
+     * For example, for each send() request, one network event will be
+     *   reported by ioqueue for the send() completion. If we don't poll
+     *   the ioqueue often enough, the send() completion will not be
+     *   reported in timely manner.
+     */
+    do {
+	c = pj_ioqueue_poll( srv->core.ioqueue, &timeout);
+	if (c < 0) {
+	    pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout));
+	    return;
+	} else if (c == 0) {
+	    break;
+	} else {
+	    net_event_count += c;
+	    timeout.sec = timeout.msec = 0;
+	}
+    } while (c > 0 && net_event_count < MAX_NET_EVENTS);
+
+}
+
+/*
+ * Server worker thread proc.
+ */
+static int server_thread_proc(void *arg)
+{
+    pj_turn_srv *srv = (pj_turn_srv*)arg;
+
+    while (!srv->core.quit) {
+	pj_time_val timeout_max = {0, 100};
+	srv_handle_events(srv, &timeout_max);
+    }
+
+    return 0;
+}
+
+/*
+ * Destroy the server.
+ */
+PJ_DEF(pj_status_t) pj_turn_srv_destroy(pj_turn_srv *srv)
+{
+    pj_hash_iterator_t itbuf, *it;
+    unsigned i;
+
+    /* Stop all worker threads */
+    srv->core.quit = PJ_TRUE;
+    for (i=0; i<srv->core.thread_cnt; ++i) {
+	if (srv->core.thread[i]) {
+	    pj_thread_join(srv->core.thread[i]);
+	    pj_thread_destroy(srv->core.thread[i]);
+	    srv->core.thread[i] = NULL;
+	}
+    }
+
+    /* Destroy all allocations FIRST */
+    if (srv->tables.alloc) {
+	it = pj_hash_first(srv->tables.alloc, &itbuf);
+	while (it != NULL) {
+	    pj_turn_allocation *alloc = (pj_turn_allocation*)
+					pj_hash_this(srv->tables.alloc, it);
+	    pj_hash_iterator_t *next = pj_hash_next(srv->tables.alloc, it);
+	    pj_turn_allocation_destroy(alloc);
+	    it = next;
+	}
+    }
+    
+    /* Destroy all listeners. */
+    for (i=0; i<srv->core.lis_cnt; ++i) {
+	if (srv->core.listener[i]) {
+	    pj_turn_listener_destroy(srv->core.listener[i]);
+	    srv->core.listener[i] = NULL;
+	}
+    }
+
+    /* Destroy STUN session */
+    if (srv->core.stun_sess) {
+	pj_stun_session_destroy(srv->core.stun_sess);
+	srv->core.stun_sess = NULL;
+    }
+
+    /* Destroy hash tables (well, sort of) */
+    if (srv->tables.alloc) {
+	srv->tables.alloc = NULL;
+	srv->tables.res = NULL;
+    }
+    
+    /* Destroy timer heap */
+    if (srv->core.timer_heap) {
+	pj_timer_heap_destroy(srv->core.timer_heap);
+	srv->core.timer_heap = NULL;
+    }
+
+    /* Destroy ioqueue */
+    if (srv->core.ioqueue) {
+	pj_ioqueue_destroy(srv->core.ioqueue);
+	srv->core.ioqueue = NULL;
+    }
+
+    /* Destroy thread local IDs */
+    if (srv->core.tls_key != -1) {
+	pj_thread_local_free(srv->core.tls_key);
+	srv->core.tls_key = -1;
+    }
+    if (srv->core.tls_data != -1) {
+	pj_thread_local_free(srv->core.tls_data);
+	srv->core.tls_data = -1;
+    }
+
+    /* Destroy server lock */
+    if (srv->core.lock) {
+	pj_lock_destroy(srv->core.lock);
+	srv->core.lock = NULL;
+    }
+
+    /* Release pool */
+    if (srv->core.pool) {
+	pj_pool_t *pool = srv->core.pool;
+	srv->core.pool = NULL;
+	pj_pool_release(pool);
+    }
+
+    /* Done */
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Add listener.
+ */
+PJ_DEF(pj_status_t) pj_turn_srv_add_listener(pj_turn_srv *srv,
+					     pj_turn_listener *lis)
+{
+    unsigned index;
+
+    PJ_ASSERT_RETURN(srv && lis, PJ_EINVAL);
+    PJ_ASSERT_RETURN(srv->core.lis_cnt < MAX_LISTENERS, PJ_ETOOMANY);
+
+    /* Add to array */
+    index = srv->core.lis_cnt;
+    srv->core.listener[index] = lis;
+    lis->server = srv;
+    lis->id = index;
+    srv->core.lis_cnt++;
+
+    PJ_LOG(4,(srv->obj_name, "Listener %s/%s added at index %d",
+	      lis->obj_name, lis->info, lis->id));
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Destroy listener.
+ */
+PJ_DEF(pj_status_t) pj_turn_listener_destroy(pj_turn_listener *listener)
+{
+    pj_turn_srv *srv = listener->server;
+    unsigned i;
+
+    /* Remove from our listener list */
+    pj_lock_acquire(srv->core.lock);
+    for (i=0; i<srv->core.lis_cnt; ++i) {
+	if (srv->core.listener[i] == listener) {
+	    srv->core.listener[i] = NULL;
+	    srv->core.lis_cnt--;
+	    listener->id = PJ_TURN_INVALID_LIS_ID;
+	    break;
+	}
+    }
+    pj_lock_release(srv->core.lock);
+
+    /* Destroy */
+    return listener->destroy(listener);
+}
+
+
+/**
+ * Add a reference to a transport.
+ */
+PJ_DEF(void) pj_turn_transport_add_ref( pj_turn_transport *transport,
+					pj_turn_allocation *alloc)
+{
+    transport->add_ref(transport, alloc);
+}
+
+
+/**
+ * Decrement transport reference counter.
+ */
+PJ_DEF(void) pj_turn_transport_dec_ref( pj_turn_transport *transport,
+					pj_turn_allocation *alloc)
+{
+    transport->dec_ref(transport, alloc);
+}
+
+
+/*
+ * Register an allocation to the hash tables.
+ */
+PJ_DEF(pj_status_t) pj_turn_srv_register_allocation(pj_turn_srv *srv,
+						    pj_turn_allocation *alloc)
+{
+    /* Add to hash tables */
+    pj_lock_acquire(srv->core.lock);
+    pj_hash_set(alloc->pool, srv->tables.alloc,
+		&alloc->hkey, sizeof(alloc->hkey), 0, alloc);
+    pj_hash_set(alloc->pool, srv->tables.res,
+		&alloc->relay.hkey, sizeof(alloc->relay.hkey), 0,
+		&alloc->relay);
+    pj_lock_release(srv->core.lock);
+
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Unregister an allocation from the hash tables.
+ */
+PJ_DEF(pj_status_t) pj_turn_srv_unregister_allocation(pj_turn_srv *srv,
+						     pj_turn_allocation *alloc)
+{
+    /* Unregister from hash tables */
+    pj_lock_acquire(srv->core.lock);
+    pj_hash_set(alloc->pool, srv->tables.alloc,
+		&alloc->hkey, sizeof(alloc->hkey), 0, NULL);
+    pj_hash_set(alloc->pool, srv->tables.res,
+		&alloc->relay.hkey, sizeof(alloc->relay.hkey), 0, NULL);
+    pj_lock_release(srv->core.lock);
+
+    return PJ_SUCCESS;
+}
+
+
+/* Callback from our own STUN session whenever it needs to send 
+ * outgoing STUN packet.
+ */
+static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
+				   void *token,
+				   const void *pdu,
+				   pj_size_t pdu_size,
+				   const pj_sockaddr_t *dst_addr,
+				   unsigned addr_len)
+{
+    pj_turn_transport *transport = (pj_turn_transport*) token;
+    
+    PJ_ASSERT_RETURN(transport!=NULL, PJ_EINVALIDOP);
+
+    PJ_UNUSED_ARG(sess);
+
+    return transport->sendto(transport, pdu, pdu_size, 0, 
+			     dst_addr, addr_len);
+}
+
+
+/* Respond to STUN request */
+static pj_status_t stun_respond(pj_stun_session *sess, 
+				pj_turn_transport *transport,
+				const pj_stun_rx_data *rdata,
+				unsigned code, 
+				const char *errmsg,
+				pj_bool_t cache, 
+				const pj_sockaddr_t *dst_addr, 
+				unsigned addr_len)
+{
+    pj_status_t status;
+    pj_str_t reason;
+    pj_stun_tx_data *tdata;
+
+    /* Create response */
+    status = pj_stun_session_create_res(sess, rdata, code, 
+					(errmsg?pj_cstr(&reason,errmsg):NULL),
+					&tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Send the response */
+    return pj_stun_session_send_msg(sess, transport, cache, PJ_FALSE, 
+				    dst_addr,  addr_len, tdata);
+}
+
+
+/* Callback from our own STUN session when incoming request arrives.
+ * This function is triggered by pj_stun_session_on_rx_pkt() call in
+ * pj_turn_srv_on_rx_pkt() function below.
+ */
+static pj_status_t on_rx_stun_request(pj_stun_session *sess,
+				      const pj_uint8_t *pdu,
+				      unsigned pdu_len,
+				      const pj_stun_rx_data *rdata,
+				      void *token,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len)
+{
+    pj_turn_transport *transport;
+    const pj_stun_msg *msg = rdata->msg;
+    pj_turn_srv *srv;
+    pj_turn_allocation *alloc;
+    pj_status_t status;
+
+    PJ_UNUSED_ARG(pdu);
+    PJ_UNUSED_ARG(pdu_len);
+
+    transport = (pj_turn_transport*) token;
+    srv = transport->listener->server;
+
+    /* Respond any requests other than ALLOCATE with 437 response */
+    if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
+	stun_respond(sess, transport, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
+		     NULL, PJ_FALSE, src_addr, src_addr_len);
+	return PJ_SUCCESS;
+    }
+
+    /* Create new allocation. The relay resource will be allocated
+     * in this function.
+     */
+    status = pj_turn_allocation_create(transport, src_addr, src_addr_len,
+				       rdata, sess, &alloc);
+    if (status != PJ_SUCCESS) {
+	/* STUN response has been sent, no need to reply here */
+	return PJ_SUCCESS;
+    }
+
+    /* Done. */
+    return PJ_SUCCESS;
+}
+
+/* Handle STUN Binding request */
+static void handle_binding_request(pj_turn_pkt *pkt,
+				   unsigned options)
+{
+    pj_stun_msg *request, *response;
+    pj_uint8_t pdu[200];
+    pj_size_t len;
+    pj_status_t status;
+
+    /* Decode request */
+    status = pj_stun_msg_decode(pkt->pool, pkt->pkt, pkt->len, options,
+				&request, NULL, NULL);
+    if (status != PJ_SUCCESS)
+	return;
+
+    /* Create response */
+    status = pj_stun_msg_create_response(pkt->pool, request, 0, NULL, 
+					 &response);
+    if (status != PJ_SUCCESS)
+	return;
+
+    /* Add XOR-MAPPED-ADDRESS */
+    pj_stun_msg_add_sockaddr_attr(pkt->pool, response, 
+				  PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+				  PJ_TRUE,
+				  &pkt->src.clt_addr,
+				  pkt->src_addr_len);
+
+    /* Encode */
+    status = pj_stun_msg_encode(response, pdu, sizeof(pdu), 0, NULL, &len);
+    if (status != PJ_SUCCESS)
+	return;
+
+    /* Send response */
+    pkt->transport->sendto(pkt->transport, pdu, len, 0, 
+			   &pkt->src.clt_addr, pkt->src_addr_len);
+}
+
+/*
+ * This callback is called by UDP listener on incoming packet. This is
+ * the first entry for incoming packet (from client) to the server. From
+ * here, the packet may be handed over to an allocation if an allocation
+ * is found for the client address, or handed over to owned STUN session
+ * if an allocation is not found.
+ */
+PJ_DEF(void) pj_turn_srv_on_rx_pkt(pj_turn_srv *srv, 
+				   pj_turn_pkt *pkt)
+{
+    pj_turn_allocation *alloc;
+
+    /* Get TURN allocation from the source address */
+    pj_lock_acquire(srv->core.lock);
+    alloc = (pj_turn_allocation*)
+	    pj_hash_get(srv->tables.alloc, &pkt->src, sizeof(pkt->src), NULL);
+    pj_lock_release(srv->core.lock);
+
+    /* If allocation is found, just hand over the packet to the
+     * allocation.
+     */
+    if (alloc) {
+	pj_turn_allocation_on_rx_client_pkt(alloc, pkt);
+    } else {
+	/* Otherwise this is a new client */
+	unsigned options;
+	pj_size_t parsed_len;
+	pj_status_t status;
+
+	/* Check that this is a STUN message */
+	options = PJ_STUN_CHECK_PACKET | PJ_STUN_NO_FINGERPRINT_CHECK;
+	if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP)
+	    options |= PJ_STUN_IS_DATAGRAM;
+
+	status = pj_stun_msg_check(pkt->pkt, pkt->len, options);
+	if (status != PJ_SUCCESS) {
+	    /* If the first byte are not STUN, drop the packet. First byte
+	     * of STUN message is always 0x00 or 0x01. Otherwise wait for
+	     * more data as the data might have come from TCP.
+	     *
+	     * Also drop packet if it's unreasonably too big, as this might
+	     * indicate invalid data that's building up in the buffer.
+	     *
+	     * Or if packet is a datagram.
+	     */
+	    if ((*pkt->pkt != 0x00 && *pkt->pkt != 0x01) ||
+		pkt->len > 1600 ||
+		(options & PJ_STUN_IS_DATAGRAM)) 
+	    {
+		char errmsg[PJ_ERR_MSG_SIZE];
+		char ip[PJ_INET6_ADDRSTRLEN+10];
+
+		pkt->len = 0;
+
+		pj_strerror(status, errmsg, sizeof(errmsg));
+		PJ_LOG(5,(srv->obj_name, 
+			  "Non-STUN packet from %s is dropped: %s",
+			  pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
+			  errmsg));
+	    }
+	    return;
+	}
+
+	/* Special handling for Binding Request. We won't give it to the 
+	 * STUN session since this request is not authenticated.
+	 */
+	if (pkt->pkt[1] == 1) {
+	    handle_binding_request(pkt, options);
+	    return;
+	}
+
+	/* Hand over processing to STUN session. This will trigger
+	 * on_rx_stun_request() callback to be called if the STUN
+	 * message is a request.
+	 */
+	options &= ~PJ_STUN_CHECK_PACKET;
+	parsed_len = 0;
+	status = pj_stun_session_on_rx_pkt(srv->core.stun_sess, pkt->pkt, 
+					   pkt->len, options, pkt->transport,
+					   &parsed_len, &pkt->src.clt_addr, 
+					   pkt->src_addr_len);
+	if (status != PJ_SUCCESS) {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    char ip[PJ_INET6_ADDRSTRLEN+10];
+
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    PJ_LOG(5,(srv->obj_name, 
+		      "Error processing STUN packet from %s: %s",
+		      pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
+		      errmsg));
+	}
+
+	if (pkt->transport->listener->tp_type == PJ_TURN_TP_UDP) {
+	    pkt->len = 0;
+	} else if (parsed_len > 0) {
+	    if (parsed_len == pkt->len) {
+		pkt->len = 0;
+	    } else {
+		pj_memmove(pkt->pkt, pkt->pkt+parsed_len,
+			   pkt->len - parsed_len);
+		pkt->len -= parsed_len;
+	    }
+	}
+    }
+}
+
+