Changed pj_sockaddr structure and added pjnath project for ICE/STUN stuffs

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1080 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjnath/src/pjnath/errno.c b/pjnath/src/pjnath/errno.c
new file mode 100644
index 0000000..bfde1bc
--- /dev/null
+++ b/pjnath/src/pjnath/errno.c
@@ -0,0 +1,121 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2007 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 <pjnath/errno.h>
+#include <pj/string.h>
+
+
+
+/* PJNATH's own error codes/messages 
+ * MUST KEEP THIS ARRAY SORTED!!
+ * Message must be limited to 64 chars!
+ */
+#if defined(PJ_HAS_ERROR_STRING) && PJ_HAS_ERROR_STRING!=0
+static const struct 
+{
+    int code;
+    const char *msg;
+} err_str[] = 
+{
+    /* STUN */
+    PJ_BUILD_ERR( PJNATH_ESTUNTOOMANYATTR,  "Too many STUN attributes"),
+    PJ_BUILD_ERR( PJNATH_ESTUNUNKNOWNATTR,  "Unknown STUN attribute"),
+    PJ_BUILD_ERR( PJNATH_ESTUNINADDRLEN,    "Invalid STUN socket address length"),
+    PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP,  "STUN IPv6 attribute not supported"),
+    PJ_BUILD_ERR( PJNATH_ESTUNNOTRESPONSE,  "Expecting STUN response message"),
+    PJ_BUILD_ERR( PJNATH_ESTUNINVALIDID,    "STUN transaction ID mismatch"),
+    PJ_BUILD_ERR( PJNATH_ESTUNNOHANDLER,    "Unable to find STUN handler for the request"),
+    PJ_BUILD_ERR( PJNATH_ESTUNMSGINTPOS,    "Found non-FINGERPRINT attr. after MESSAGE-INTEGRITY"),
+    PJ_BUILD_ERR( PJNATH_ESTUNFINGERPOS,    "Found STUN attribute after FINGERPRINT"),
+    PJ_BUILD_ERR( PJNATH_ESTUNNOUSERNAME,   "Missing STUN USERNAME attribute"),
+    PJ_BUILD_ERR( PJNATH_ESTUNMSGINT,	    "Missing/invalid STUN MESSAGE-INTEGRITY attribute"),
+    PJ_BUILD_ERR( PJNATH_ESTUNDUPATTR,	    "Found duplicate STUN attribute"),
+    PJ_BUILD_ERR( PJNATH_ESTUNNOREALM,	    "Missing STUN REALM attribute"),
+    PJ_BUILD_ERR( PJNATH_ESTUNNONCE,	    "Missing/stale STUN NONCE attribute value"),
+    PJ_BUILD_ERR( PJNATH_ESTUNTSXFAILED,    "STUN transaction terminates with failure"),
+};
+#endif	/* PJ_HAS_ERROR_STRING */
+
+
+/*
+ * pjnath_strerror()
+ */
+PJ_DEF(pj_str_t) pjnath_strerror( pj_status_t statcode, 
+				  char *buf, pj_size_t bufsize )
+{
+    pj_str_t errstr;
+
+#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
+
+    if (statcode >= PJNATH_ERRNO_START && 
+	statcode < PJNATH_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
+    {
+	/* Find the error in the table.
+	 * Use binary search!
+	 */
+	int first = 0;
+	int n = PJ_ARRAY_SIZE(err_str);
+
+	while (n > 0) {
+	    int half = n/2;
+	    int mid = first + half;
+
+	    if (err_str[mid].code < statcode) {
+		first = mid+1;
+		n -= (half+1);
+	    } else if (err_str[mid].code > statcode) {
+		n = half;
+	    } else {
+		first = mid;
+		break;
+	    }
+	}
+
+
+	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
+	    pj_str_t msg;
+	    
+	    msg.ptr = (char*)err_str[first].msg;
+	    msg.slen = pj_ansi_strlen(err_str[first].msg);
+
+	    errstr.ptr = buf;
+	    pj_strncpy_with_null(&errstr, &msg, bufsize);
+	    return errstr;
+
+	} 
+    }
+
+#endif	/* PJ_HAS_ERROR_STRING */
+
+
+    /* Error not found. */
+    errstr.ptr = buf;
+    errstr.slen = pj_ansi_snprintf(buf, bufsize, 
+				   "Unknown pjlib-util error %d",
+				   statcode);
+
+    return errstr;
+}
+
+
+PJ_DEF(pj_status_t) pjnath_init(void)
+{
+    return pj_register_strerror(PJNATH_ERRNO_START, 
+				PJ_ERRNO_SPACE_SIZE, 
+				&pjnath_strerror);
+}
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c
new file mode 100644
index 0000000..c92ceb5
--- /dev/null
+++ b/pjnath/src/pjnath/ice.c
@@ -0,0 +1,566 @@
+/* $Id$ */
+/* 
+ * Copyright (C) 2003-2005 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 <pjnath/ice.h>
+#include <pjnath/errno.h>
+#include <pj/assert.h>
+#include <pj/os.h>
+#include <pj/pool.h>
+#include <pj/string.h>
+
+
+static void destroy_ice(pj_ice *ice,
+			pj_status_t reason);
+static void ice_set_state(pj_ice *ice,
+			  pj_ice_state new_state);
+
+
+PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *cfg,
+				  const char *name,
+				  int af,
+				  int sock_type,
+				  pj_ice **p_ice)
+{
+    pj_pool_t *pool;
+    pj_ice *ice;
+    pj_status_t status;
+
+    PJ_ASSERT_RETURN(cfg && p_ice, PJ_EINVAL);
+    PJ_ASSERT_RETURN(sock_type==PJ_SOCK_DGRAM || sock_type==PJ_SOCK_STREAM,
+		     PJ_EINVAL);
+
+    if (!name)
+	name = "ice%p";
+
+    pool = pj_pool_create(cfg->pf, name, 4000, 4000, NULL);
+    ice = PJ_POOL_ZALLOC_T(pool, pj_ice);
+    ice->pool = pool;
+    ice->af = af;
+    ice->sock_type = sock_type;
+
+    pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
+		     name, ice);
+
+    status = pj_mutex_create_recursive(pool, ice->obj_name, 
+				       &ice->mutex);
+    if (status != PJ_SUCCESS) {
+	destroy_ice(ice, status);
+	return status;
+    }
+
+    *p_ice = ice;
+
+    return PJ_SUCCESS;
+}
+
+
+static void destroy_ice(pj_ice *ice,
+			pj_status_t reason)
+{
+    if (ice->resv_q) {
+	pj_dns_resolver_cancel_query(ice->resv_q, PJ_FALSE);
+	ice->resv_q = NULL;
+    }
+
+    if (ice->mutex) {
+	pj_mutex_destroy(ice->mutex);
+	ice->mutex = NULL;
+    }
+
+    if (ice->pool) {
+	pj_pool_t *pool = ice->pool;
+	ice->pool = NULL;
+	pj_pool_release(pool);
+    }
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_destroy(pj_ice *ice)
+{
+    destroy_ice(ice, PJ_SUCCESS);
+    return PJ_SUCCESS;
+}
+
+
+static void ice_set_state(pj_ice *ice,
+			  pj_ice_state new_state)
+{
+    ice->state = new_state;
+}
+
+static void resolver_cb(void *user_data,
+			pj_status_t status,
+			pj_dns_parsed_packet *response)
+{
+    pj_assert(!"Not implemented yet!");
+}
+
+PJ_DEF(pj_status_t) pj_ice_set_srv(pj_ice *ice,
+				   pj_bool_t enable_relay,
+				   pj_dns_resolver *resolver,
+				   const pj_str_t *domain)
+{
+    char namebuf[128];
+    char *tp_name;
+    pj_str_t name;
+    pj_status_t status;
+
+
+    /* Not implemented yet! */
+    return PJ_ENOTSUP;
+
+
+    PJ_ASSERT_RETURN(ice && resolver && domain, PJ_EINVAL);
+
+    /* Must not have a running resolver. This is because we couldn't
+     * safely cancel the query (there is a race condition situation
+     * between the callback acquiring the mutex and this function
+     * acquiring the mutex)
+     */
+    PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY);
+
+    pj_mutex_lock(ice->mutex);
+
+    /* Reset resolver and server addresses */
+    ice->relay_enabled = enable_relay;
+    ice->resv = resolver;
+    pj_bzero(&ice->stun_srv, sizeof(ice->stun_srv));
+
+    /* Build SRV record name */
+    if (ice->sock_type == PJ_SOCK_DGRAM) {
+	tp_name = "_udp";
+    } else if (ice->sock_type == PJ_SOCK_STREAM) {
+	tp_name = "_tcp";
+    } else {
+	pj_assert(!"Invalid sock_type");
+	pj_mutex_unlock(ice->mutex);
+	return PJ_EBUG;
+    }
+
+    if (enable_relay) {
+	name.ptr = namebuf;
+	name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf),
+				     "_stun-relay.%s.%.*s",
+				     tp_name,
+				     (int)domain->slen,
+				     domain->ptr);
+    } else {
+	name.ptr = namebuf;
+	name.slen = pj_ansi_snprintf(namebuf, sizeof(namebuf),
+				     "_stun.%s.%.*s",
+				     tp_name,
+				     (int)domain->slen,
+				     domain->ptr);
+    }
+
+    if (name.slen < 1 || name.slen >= sizeof(namebuf)) {
+	pj_mutex_unlock(ice->mutex);
+	return PJ_ENAMETOOLONG;
+    }
+
+    /* Start DNS query */
+    status = pj_dns_resolver_start_query(ice->resv, &name, 
+					 PJ_DNS_TYPE_SRV, 0, 
+					 &resolver_cb, 
+					 ice, &ice->resv_q);
+    if (status != PJ_SUCCESS) {
+	pj_mutex_unlock(ice->mutex);
+	return status;
+    }
+
+    pj_mutex_unlock(ice->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_set_srv_addr(pj_ice *ice,
+					pj_bool_t enable_relay,
+					const pj_sockaddr_t *srv_addr,
+					unsigned addr_len)
+{
+    PJ_ASSERT_RETURN(ice && srv_addr, PJ_EINVAL);
+    /* Must not have a running resolver. This is because we couldn't
+     * safely cancel the query (there is a race condition situation
+     * between the callback acquiring the mutex and this function
+     * acquiring the mutex)
+     */
+    PJ_ASSERT_RETURN(ice->resv_q==NULL, PJ_EBUSY);
+
+    pj_mutex_lock(ice->mutex);
+
+    ice->relay_enabled = enable_relay;
+    pj_memcpy(&ice->stun_srv, srv_addr, addr_len);
+
+    pj_mutex_unlock(ice->mutex);
+
+    return PJ_SUCCESS;
+
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice,
+				    unsigned comp_id,
+				    const pj_sockaddr_t *local_addr,
+				    unsigned addr_len)
+{
+    pj_status_t status;
+    pj_sock_t sock;
+
+    PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL);
+
+    status = pj_sock_socket(ice->af, ice->sock_type, 0, &sock);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_sock_bind(sock, local_addr, addr_len);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_ice_add_sock_comp(ice, comp_id, sock);
+    if (status != PJ_SUCCESS) {
+	pj_sock_close(sock);
+	return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_add_sock_comp( pj_ice *ice,
+					  unsigned comp_id,
+					  pj_sock_t sock)
+{
+    PJ_ASSERT_RETURN(ice && sock != PJ_INVALID_SOCKET, PJ_EINVAL);
+    PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY);
+
+    pj_mutex_lock(ice->mutex);
+    ice->comp[ice->comp_cnt].comp_id = comp_id;
+    ice->comp[ice->comp_cnt].sock = sock;
+    ++ice->comp_cnt;
+    pj_mutex_unlock(ice->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t gather_host_cands(pj_ice *ice)
+{
+    unsigned i;
+    pj_status_t status;
+
+    for (i=0; i<ice->comp_cnt; ++i) {
+	pj_ice_comp *comp = &ice->comp[i];
+	pj_sockaddr addr;
+	int addr_len;
+
+	addr_len = sizeof(addr);
+	status = pj_sock_getsockname(comp->sock, &addr, &addr_len);
+	if (status != PJ_SUCCESS)
+	    return status;
+
+	if (addr.ipv4.sin_addr.s_addr == 0) {
+	    status = pj_gethostip(&addr.ipv4.sin_addr);
+	    if (status != PJ_SUCCESS)
+		return status;
+	}
+
+	status = pj_ice_add_cand(ice, i, PJ_ICE_CAND_TYPE_HOST, 65535,
+				 NULL, &addr, &addr, NULL,
+    				 sizeof(pj_sockaddr_in), NULL);
+	if (status != PJ_SUCCESS)
+	    return status;
+    }
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t gather_mapped_cands(pj_ice *ice)
+{
+    return PJ_ENOTSUP;
+}
+
+static pj_status_t gather_relayed_cands(pj_ice *ice)
+{
+    return PJ_ENOTSUP;
+}
+
+PJ_DEF(pj_status_t) pj_ice_start_gather(pj_ice *ice,
+					unsigned flags)
+{
+    pj_status_t status;
+
+    /* Gather host candidate */
+    status = gather_host_cands(ice);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    PJ_TODO(GATHER_MAPPED_AND_RELAYED_CANDIDATES);
+
+    ice_set_state(ice, PJ_ICE_STATE_CAND_COMPLETE);
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type,
+				  pj_uint32_t local_pref,
+				  pj_uint32_t comp_id)
+{
+    static pj_uint32_t type_pref[] =
+    {
+	PJ_ICE_HOST_PREF,
+	PJ_ICE_MAPPED_PREF,
+	PJ_ICE_PEER_MAPPED_PREF,
+	PJ_ICE_RELAYED_PREF
+    };
+
+    return ((1 << 24) * type_pref[type]) + 
+	   ((1 << 8) * local_pref) +
+	   (256 - comp_id);
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
+				    unsigned comp_id,
+				    pj_ice_cand_type type,
+				    pj_uint16_t local_pref,
+				    const pj_str_t *foundation,
+				    const pj_sockaddr_t *addr,
+				    const pj_sockaddr_t *base_addr,
+				    const pj_sockaddr_t *srv_addr,
+				    int addr_len,
+				    unsigned *p_cand_id)
+{
+    pj_ice_cand *cand;
+    pj_status_t status = PJ_SUCCESS;
+
+    pj_mutex_lock(ice->mutex);
+
+    if (ice->cand_cnt >= PJ_ARRAY_SIZE(ice->cand)) {
+	status = PJ_ETOOMANY;
+	goto on_error;
+    }
+
+    cand = &ice->cand[ice->cand_cnt];
+    cand->comp_id = comp_id;
+    cand->type = type;
+    pj_strdup(ice->pool, &cand->foundation, foundation);
+    cand->prio = CALC_CAND_PRIO(type, local_pref, cand->comp_id);
+    pj_memcpy(&cand->addr, addr, addr_len);
+    pj_memcpy(&cand->base_addr, base_addr, addr_len);
+    if (srv_addr)
+	pj_memcpy(&cand->srv_addr, srv_addr, addr_len);
+    else
+	pj_bzero(&cand->srv_addr, sizeof(cand->srv_addr));
+
+    if (p_cand_id)
+	*p_cand_id = ice->cand_cnt;
+
+    ++ice->cand_cnt;
+
+on_error:
+    pj_mutex_unlock(ice->mutex);
+    return status;
+}
+
+
+PJ_DEF(unsigned) pj_ice_get_cand_cnt(pj_ice *ice)
+{
+    return ice->cand_cnt;
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice,
+				      unsigned sort_by,
+				      unsigned *p_count,
+				      unsigned cand_ids[])
+{
+    unsigned i, count;
+
+    pj_mutex_lock(ice->mutex);
+
+    count = (*p_count < ice->cand_cnt) ? *p_count : ice->cand_cnt;
+    for (i=0; i<count; ++i)
+	cand_ids[i] = i;
+
+    *p_count = count;
+    pj_mutex_unlock(ice->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice,
+				    unsigned cand_id,
+				    pj_ice_cand **p_cand)
+{
+    PJ_ASSERT_RETURN(ice && p_cand, PJ_EINVAL);
+    PJ_ASSERT_RETURN(cand_id <= ice->cand_cnt, PJ_EINVAL);
+
+    *p_cand = &ice->cand[cand_id];
+
+    return PJ_SUCCESS;
+}
+
+#ifndef MIN
+#   define MIN(a,b) (a < b ? a : b)
+#endif
+
+#ifndef MAX
+#   define MAX(a,b) (a > b ? a : b)
+#endif
+
+static pj_uint64_t CALC_CHECK_PRIO(pj_uint32_t O, pj_uint32_t A)
+{
+    return ((pj_uint64_t)1 << 32) * MIN(O, A) +
+	   (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
+}
+
+
+PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice,
+					     pj_bool_t is_remote_offer,
+					     unsigned rem_cand_cnt,
+					     const pj_ice_cand rem_cand[])
+{
+    pj_ice_checklist *clist;
+    unsigned i, j, count;
+
+    PJ_ASSERT_RETURN(ice && rem_cand_cnt && rem_cand, PJ_EINVAL);
+
+    pj_mutex_lock(ice->mutex);
+
+    /* Create checklist */
+    clist = &ice->cklist;
+    clist->checks = pj_pool_calloc(ice->pool, 
+				   ice->cand_cnt * rem_cand_cnt,
+				   sizeof(pj_ice_check));
+    for (i=0, count=0; i<ice->cand_cnt; ++i) {
+	for (j=0; j<rem_cand_cnt; ++j) {
+
+	    pj_ice_check *c = &clist->checks[count++];
+
+	    /* A local candidate is paired with a remote candidate if
+	     * and only if the two candidates have the same component ID 
+	     * and have the same IP address version. 
+	     */
+	    if (ice->cand[i].comp_id != rem_cand[j].comp_id ||
+		pj_strcmp(&ice->cand[i].foundation,&rem_cand[j].foundation)==0)
+	    {
+		continue;
+	    }
+
+	    c->local_cand_id = i;
+
+	    if (is_remote_offer) {
+		c->check_prio = CALC_CHECK_PRIO(rem_cand[j].prio,
+						ice->cand[i].prio);
+	    } else {
+		c->check_prio = CALC_CHECK_PRIO(ice->cand[i].prio, 
+						rem_cand[j].prio);
+	    }
+
+	    c->rem_type = rem_cand[j].type;
+	    pj_strdup(ice->pool, &c->rem_foundation, &rem_cand[j].foundation);
+	    c->rem_prio = rem_cand[j].prio;
+	    pj_memcpy(&c->rem_addr, &rem_cand[j].addr, 
+		      sizeof(rem_cand[j].addr));
+	    pj_memcpy(&c->rem_base_addr, &rem_cand[j].base_addr, 
+		      sizeof(rem_cand[j].addr));
+	}
+    }
+
+    clist->count = count;
+
+    /* Sort checklist based on priority */
+    for (i=0; i<clist->count-1; ++i) {
+	unsigned highest = i;
+	for (j=i+1; j<clist->count; ++j) {
+	    if (clist->checks[j].check_prio > 
+		clist->checks[highest].check_prio) 
+	    {
+		highest = j;
+	    }
+	}
+
+	if (highest != i) {
+	    pj_ice_check tmp;
+
+	    pj_memcpy(&tmp, &clist->checks[i], sizeof(pj_ice_check));
+	    pj_memcpy(&clist->checks[i], &clist->checks[highest], 
+		      sizeof(pj_ice_check));
+	    pj_memcpy(&clist->checks[highest], &tmp, sizeof(pj_ice_check));
+	}
+    }
+
+    /* Prune the checklist */
+    for (i=0; i<clist->count; ++i) {
+	PJ_TODO(PRUNE_CHECKLIST);
+    }
+
+    pj_mutex_lock(ice->mutex);
+
+    return PJ_SUCCESS;
+}
+
+
+/* Start periodic check for the specified checklist */
+static pj_status_t start_periodic_check(pj_ice *ice, pj_ice_checklist *clist)
+{
+}
+
+
+/* Start ICE check */
+PJ_DEF(pj_status_t) pj_ice_start_check(pj_ice *ice)
+{
+    pj_ice_checklist *clist;
+    unsigned i, comp_id;
+    pj_str_t fnd;
+
+    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+
+    clist = &ice->cklist;
+
+    if (clist->count == 0)
+	return PJ_EICENOCHECKLIST;
+
+    /* Pickup the first pair and set the state to Waiting */
+    clist->checks[0].check_state = PJ_ICE_CHECK_STATE_WAITING;
+
+    /* Find all of the other pairs in that check list with the same
+     * component ID, but different foundations, and sets all of their
+     * states to Waiting as well.
+     */
+    comp_id = ice->cand[clist->checks[0].local_cand_id].comp_id;
+    fnd = ice->cand[clist->checks[0].local_cand_id].foundation;
+
+    for (i=1; i<clist->count; ++i) {
+	pj_ice_check *cki = &clist->checks[i];
+
+	if (ice->cand[cki->local_cand_id].comp_id != comp_id)
+	    continue;
+
+	if (pj_strcmp(&ice->cand[cki->local_cand_id].foundation, &fnd)==0)
+	    continue;
+
+	clist->checks[i].check_state = PJ_ICE_CHECK_STATE_WAITING;
+    }
+
+    /* Start periodic check */
+    return start_periodic_check(ice, clist);
+}
diff --git a/pjnath/src/pjnath/stun_auth.c b/pjnath/src/pjnath/stun_auth.c
index 9a94fe0..071019b 100644
--- a/pjnath/src/pjnath/stun_auth.c
+++ b/pjnath/src/pjnath/stun_auth.c
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_auth.h>
-#include <pjlib-util/errno.h>
+#include <pjnath/stun_auth.h>
+#include <pjnath/errno.h>
 #include <pjlib-util/hmac_sha1.h>
 #include <pjlib-util/sha1.h>
 #include <pj/assert.h>
@@ -159,7 +159,7 @@
 	    create_challenge(pool, msg, PJ_STUN_SC_UNAUTHORIZED, NULL,
 			     &realm, &nonce, p_response);
 	}
-	return PJLIB_UTIL_ESTUNMSGINT;
+	return PJNATH_ESTUNMSGINT;
     }
 
     /* Next check that USERNAME is present */
@@ -170,7 +170,7 @@
 	    create_challenge(pool, msg, PJ_STUN_SC_MISSING_USERNAME, NULL,
 			     &realm, &nonce, p_response);
 	}
-	return PJLIB_UTIL_ESTUNNOUSERNAME;
+	return PJNATH_ESTUNNOUSERNAME;
     }
 
     /* Get REALM, if any */
@@ -201,7 +201,7 @@
 	    create_challenge(pool, msg, PJ_STUN_SC_UNKNOWN_USERNAME, NULL,
 			     &realm, &nonce, p_response);
 	}
-	return PJLIB_UTIL_ESTUNUSERNAME;
+	return PJNATH_ESTUNUSERNAME;
     }
 
 
@@ -216,7 +216,7 @@
 	    create_challenge(pool, msg, PJ_STUN_SC_MISSING_REALM, NULL,
 			     &realm, &nonce, p_response);
 	}
-	return PJLIB_UTIL_ESTUNNOREALM;
+	return PJNATH_ESTUNNOREALM;
 
     } else if (realm.slen != 0 && arealm != NULL) {
 	/* We want long term, and REALM is present */
@@ -227,7 +227,7 @@
 		create_challenge(pool, msg, PJ_STUN_SC_MISSING_NONCE, 
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJLIB_UTIL_ESTUNNONCE;
+	    return PJNATH_ESTUNNONCE;
 	}
 
 	/* Verify REALM matches */
@@ -237,7 +237,7 @@
 		create_challenge(pool, msg, PJ_STUN_SC_MISSING_REALM, 
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJLIB_UTIL_ESTUNNOREALM;
+	    return PJNATH_ESTUNNOREALM;
 	}
 
 	/* Valid case, will validate the message integrity later */
@@ -260,7 +260,7 @@
 		create_challenge(pool, msg, PJ_STUN_SC_MISSING_NONCE, 
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJLIB_UTIL_ESTUNNONCE;
+	    return PJNATH_ESTUNNONCE;
 	}
     }
 
@@ -286,7 +286,7 @@
 		create_challenge(pool, msg, PJ_STUN_SC_STALE_NONCE, 
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJLIB_UTIL_ESTUNNONCE;
+	    return PJNATH_ESTUNNONCE;
 	}
     }
 
@@ -331,7 +331,7 @@
 	    create_challenge(pool, msg, PJ_STUN_SC_INTEGRITY_CHECK_FAILURE,
 			     NULL, &realm, &nonce, p_response);
 	}
-	return PJLIB_UTIL_ESTUNMSGINT;
+	return PJNATH_ESTUNMSGINT;
     }
 
     /* Everything looks okay! */
diff --git a/pjnath/src/pjnath/stun_endpoint.c b/pjnath/src/pjnath/stun_endpoint.c
index 277e385..3be6407 100644
--- a/pjnath/src/pjnath/stun_endpoint.c
+++ b/pjnath/src/pjnath/stun_endpoint.c
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_endpoint.h>
-#include <pjlib-util/errno.h>
+#include <pjnath/stun_endpoint.h>
+#include <pjnath/errno.h>
 #include <pj/assert.h>
 #include <pj/pool.h>
 
@@ -25,14 +25,14 @@
 /*
  * Create a STUN endpoint instance.
  */
-PJ_DEF(pj_status_t) pj_stun_endpoint_create( pj_pool_factory *factory,
-					     unsigned options,
-					     pj_ioqueue_t *ioqueue,
-					     pj_timer_heap_t *timer_heap,
-					     pj_stun_endpoint **p_endpt)
+PJ_DEF(pj_status_t) pj_stun_config_create( pj_pool_factory *factory,
+					   unsigned options,
+					   pj_ioqueue_t *ioqueue,
+					   pj_timer_heap_t *timer_heap,
+					   pj_stun_config **p_endpt)
 {
     pj_pool_t *pool;
-    pj_stun_endpoint *endpt;
+    pj_stun_config *endpt;
 
     PJ_ASSERT_RETURN(factory && p_endpt, PJ_EINVAL);
 
@@ -40,7 +40,7 @@
     if (!pool)
 	return PJ_ENOMEM;
     
-    endpt = PJ_POOL_ZALLOC_T(pool, pj_stun_endpoint);
+    endpt = PJ_POOL_ZALLOC_T(pool, pj_stun_config);
     endpt->pool = pool;
     endpt->pf = factory;
     endpt->options = options;
@@ -58,7 +58,7 @@
 /*
  * Destroy STUN endpoint instance.
  */
-PJ_DEF(pj_status_t) pj_stun_endpoint_destroy(pj_stun_endpoint *endpt)
+PJ_DEF(pj_status_t) pj_stun_config_destroy(pj_stun_config *endpt)
 {
     PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
 
diff --git a/pjnath/src/pjnath/stun_msg.c b/pjnath/src/pjnath/stun_msg.c
index 1c750d8..b361898 100644
--- a/pjnath/src/pjnath/stun_msg.c
+++ b/pjnath/src/pjnath/stun_msg.c
@@ -16,9 +16,9 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_msg.h>
+#include <pjnath/stun_msg.h>
+#include <pjnath/errno.h>
 #include <pjlib-util/crc32.h>
-#include <pjlib-util/errno.h>
 #include <pjlib-util/hmac_sha1.h>
 #include <pjlib-util/md5.h>
 #include <pj/assert.h>
@@ -558,7 +558,7 @@
     attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
     INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
 
-    pj_memcpy(&attr->addr, addr, addr_len);
+    pj_memcpy(&attr->sockaddr, addr, addr_len);
     attr->xor_ed = xor_ed;
 
     *p_attr = attr;
@@ -606,19 +606,19 @@
 
     /* Check that the attribute length is valid */
     if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
-	return PJLIB_UTIL_ESTUNINATTRLEN;
+	return PJNATH_ESTUNINATTRLEN;
 
     /* Check address family */
     val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
 
     /* Check address family is valid (only supports ipv4 for now) */
     if (val != 1)
-	return PJLIB_UTIL_ESTUNIPV6NOTSUPP;
+	return PJNATH_ESTUNIPV6NOTSUPP;
 
     /* Get port and address */
-    pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
-    pj_memcpy(&attr->addr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
-    pj_memcpy(&attr->addr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
+    pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
+    pj_memcpy(&attr->sockaddr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
+    pj_memcpy(&attr->sockaddr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
 
     /* Done */
     *p_attr = attr;
@@ -644,22 +644,22 @@
 
     /* Check that the attribute length is valid */
     if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
-	return PJLIB_UTIL_ESTUNINATTRLEN;
+	return PJNATH_ESTUNINATTRLEN;
 
     /* Check address family */
     val = *(pj_uint8_t*)(buf + ATTR_HDR_LEN + 1);
 
     /* Check address family is valid (only supports ipv4 for now) */
     if (val != 1)
-	return PJLIB_UTIL_ESTUNIPV6NOTSUPP;
+	return PJNATH_ESTUNIPV6NOTSUPP;
 
     /* Get port and address */
-    pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
-    pj_memcpy(&attr->addr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
-    pj_memcpy(&attr->addr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
+    pj_sockaddr_in_init(&attr->sockaddr.ipv4, NULL, 0);
+    pj_memcpy(&attr->sockaddr.ipv4.sin_port, buf+ATTR_HDR_LEN+2, 2);
+    pj_memcpy(&attr->sockaddr.ipv4.sin_addr, buf+ATTR_HDR_LEN+4, 4);
 
-    attr->addr.ipv4.sin_port ^= 0x2112;
-    attr->addr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
+    attr->sockaddr.ipv4.sin_port ^= pj_htons(0x2112);
+    attr->sockaddr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
 
     /* Done */
     *p_attr = attr;
@@ -693,17 +693,17 @@
     *buf++ = '\0';
 
     /* Family (IPv4 only for now) */
-    PJ_ASSERT_RETURN(ca->addr.addr.sa_family == PJ_AF_INET, PJ_EINVAL);
+    PJ_ASSERT_RETURN(ca->sockaddr.addr.sa_family == PJ_AF_INET, PJ_EINVAL);
     *buf++ = 1;
 
     if (ca->xor_ed) {
 	pj_uint32_t addr;
 	pj_uint16_t port;
 
-	addr = ca->addr.ipv4.sin_addr.s_addr;
-	port = ca->addr.ipv4.sin_port;
+	addr = ca->sockaddr.ipv4.sin_addr.s_addr;
+	port = ca->sockaddr.ipv4.sin_port;
 
-	port ^= 0x2112;
+	port ^= pj_htons(0x2112);
 	addr ^= pj_htonl(0x2112A442);
 
 	/* Port */
@@ -716,11 +716,11 @@
 
     } else {
 	/* Port */
-	pj_memcpy(buf, &ca->addr.ipv4.sin_port, 2);
+	pj_memcpy(buf, &ca->sockaddr.ipv4.sin_port, 2);
 	buf += 2;
 
 	/* Address */
-	pj_memcpy(buf, &ca->addr.ipv4.sin_addr, 4);
+	pj_memcpy(buf, &ca->sockaddr.ipv4.sin_addr, 4);
 	buf += 4;
     }
 
@@ -892,7 +892,7 @@
 
     /* Check that the attribute length is valid */
     if (attr->hdr.length != ATTR_HDR_LEN)
-	return PJLIB_UTIL_ESTUNINATTRLEN;
+	return PJNATH_ESTUNINATTRLEN;
 
     /* Done */
     *p_attr = attr;
@@ -992,7 +992,7 @@
 
     /* Check that the attribute length is valid */
     if (attr->hdr.length != STUN_UINT_LEN)
-	return PJLIB_UTIL_ESTUNINATTRLEN;
+	return PJNATH_ESTUNINATTRLEN;
 
     /* Done */
     *p_attr = attr;
@@ -1088,7 +1088,7 @@
 
     /* Check that the attribute length is valid */
     if (attr->hdr.length != STUN_MSG_INTEGRITY_LEN)
-	return PJLIB_UTIL_ESTUNINATTRLEN;
+	return PJNATH_ESTUNINATTRLEN;
 
     /* Done */
     *p_attr = attr;
@@ -1563,18 +1563,18 @@
     PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
 
     if (pdu_len < sizeof(pj_stun_msg_hdr))
-	return PJLIB_UTIL_ESTUNINMSGLEN;
+	return PJNATH_ESTUNINMSGLEN;
 
     /* First byte of STUN message is always 0x00 or 0x01. */
     if (*pdu != 0x00 && *pdu != 0x01)
-	return PJLIB_UTIL_ESTUNINMSGTYPE;
+	return PJNATH_ESTUNINMSGTYPE;
 
     /* Check the PDU length */
     msg_len = GET_VAL16(pdu, 2);
     if ((msg_len + 20 > pdu_len) || 
 	((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len))
     {
-	return PJLIB_UTIL_ESTUNINMSGLEN;
+	return PJNATH_ESTUNINMSGLEN;
     }
 
     /* If magic is set, then there is great possibility that this is
@@ -1589,13 +1589,13 @@
 	    pj_uint32_t crc;
 
 	    if (attr_len != 4)
-		return PJLIB_UTIL_ESTUNINATTRLEN;
+		return PJNATH_ESTUNINATTRLEN;
 
 	    crc = pj_crc32_calc(pdu, msg_len + 20);
 	    crc ^= STUN_XOR_FINGERPRINT;
 
 	    if (crc != fingerprint)
-		return PJLIB_UTIL_ESTUNFINGERPRINT;
+		return PJNATH_ESTUNFINGERPRINT;
 	}
     }
 
@@ -1618,7 +1618,7 @@
     PJ_ASSERT_RETURN(pool && p_response, PJ_EINVAL);
 
     PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type), 
-		     PJLIB_UTIL_ESTUNINMSGTYPE);
+		     PJNATH_ESTUNINMSGTYPE);
 
     /* Create response or error response */
     if (err_code)
@@ -1728,7 +1728,7 @@
 					    PJ_STUN_SC_BAD_REQUEST, 
 					    &err_msg, p_response);
 	    }
-	    return PJLIB_UTIL_ESTUNINATTRLEN;
+	    return PJNATH_ESTUNINATTRLEN;
 	}
 
 	/* Get the attribute descriptor */
@@ -1757,7 +1757,7 @@
 		    }
 		}
 
-		return PJLIB_UTIL_ESTUNUNKNOWNATTR;
+		return PJNATH_ESTUNUNKNOWNATTR;
 	    }
 
 	} else {
@@ -1805,7 +1805,7 @@
 						    PJ_STUN_SC_BAD_REQUEST,
 						    NULL, p_response);
 		    }
-		    return PJLIB_UTIL_ESTUNDUPATTR;
+		    return PJNATH_ESTUNDUPATTR;
 		}
 		has_msg_int = PJ_TRUE;
 
@@ -1819,7 +1819,7 @@
 						    PJ_STUN_SC_BAD_REQUEST,
 						    NULL, p_response);
 		    }
-		    return PJLIB_UTIL_ESTUNDUPATTR;
+		    return PJNATH_ESTUNDUPATTR;
 		}
 		has_fingerprint = PJ_TRUE;
 	    } else {
@@ -1833,8 +1833,8 @@
 						    PJ_STUN_SC_BAD_REQUEST,
 						    NULL, p_response);
 		    }
-		    return has_fingerprint ? PJLIB_UTIL_ESTUNFINGERPOS :
-					     PJLIB_UTIL_ESTUNMSGINTPOS;
+		    return has_fingerprint ? PJNATH_ESTUNFINGERPOS :
+					     PJNATH_ESTUNMSGINTPOS;
 		}
 	    }
 
@@ -1848,7 +1848,7 @@
 						PJ_STUN_SC_BAD_REQUEST,
 						&e, p_response);
 		}
-		return PJLIB_UTIL_ESTUNTOOMANYATTR;
+		return PJNATH_ESTUNTOOMANYATTR;
 	    }
 
 	    /* Add the attribute */
@@ -2027,12 +2027,12 @@
 	const pj_stun_attr_hdr *attr_hdr = msg->attr[i];
 
 	/* There mustn't any attribute after FINGERPRINT */
-	PJ_ASSERT_RETURN(afingerprint == NULL, PJLIB_UTIL_ESTUNFINGERPOS);
+	PJ_ASSERT_RETURN(afingerprint == NULL, PJNATH_ESTUNFINGERPOS);
 
 	if (attr_hdr->type == PJ_STUN_ATTR_MESSAGE_INTEGRITY) {
 	    /* There mustn't be MESSAGE-INTEGRITY before */
 	    PJ_ASSERT_RETURN(amsgint == NULL, 
-			     PJLIB_UTIL_ESTUNMSGINTPOS);
+			     PJNATH_ESTUNMSGINTPOS);
 	    amsgint = (pj_stun_msgint_attr*) attr_hdr;
 
 	} else if (attr_hdr->type == PJ_STUN_ATTR_FINGERPRINT) {
@@ -2070,13 +2070,13 @@
 	if (i < msg->attr_count-2) {
 	    /* Should not happen for message generated by us */
 	    pj_assert(PJ_FALSE);
-	    return PJLIB_UTIL_ESTUNMSGINTPOS;
+	    return PJNATH_ESTUNMSGINTPOS;
 
 	} else if (i == msg->attr_count-2)  {
 	    if (msg->attr[i+1]->type != PJ_STUN_ATTR_FINGERPRINT) {
 		/* Should not happen for message generated by us */
 		pj_assert(PJ_FALSE);
-		return PJLIB_UTIL_ESTUNMSGINTPOS;
+		return PJNATH_ESTUNMSGINTPOS;
 	    } else {
 		afingerprint = (pj_stun_fingerprint_attr*) msg->attr[i+1];
 	    }
@@ -2086,7 +2086,7 @@
 	if (auname == NULL) {
 	    /* Should not happen for message generated by us */
 	    pj_assert(PJ_FALSE);
-	    return PJLIB_UTIL_ESTUNNOUSERNAME;
+	    return PJNATH_ESTUNNOUSERNAME;
 	}
 
 	/* Password must be specified */
diff --git a/pjnath/src/pjnath/stun_msg_dump.c b/pjnath/src/pjnath/stun_msg_dump.c
index 0ee0ebe..5e83958 100644
--- a/pjnath/src/pjnath/stun_msg_dump.c
+++ b/pjnath/src/pjnath/stun_msg_dump.c
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_msg.h>
-#include <pjlib-util/errno.h>
+#include <pjnath/stun_msg.h>
+#include <pjnath/errno.h>
 #include <pj/assert.h>
 #include <pj/string.h>
 
@@ -80,13 +80,13 @@
 
 	    attr = (const pj_stun_sockaddr_attr*)ahdr;
 
-	    if (attr->addr.addr.sa_family == PJ_AF_INET) {
+	    if (attr->sockaddr.addr.sa_family == PJ_AF_INET) {
 		len = pj_ansi_snprintf(p, end-p,
 				       ", IPv4 addr=%s:%d\n",
-				       pj_inet_ntoa(attr->addr.ipv4.sin_addr),
-				       pj_ntohs(attr->addr.ipv4.sin_port));
+				       pj_inet_ntoa(attr->sockaddr.ipv4.sin_addr),
+				       pj_ntohs(attr->sockaddr.ipv4.sin_port));
 
-	    } else if (attr->addr.addr.sa_family == PJ_AF_INET6) {
+	    } else if (attr->sockaddr.addr.sa_family == PJ_AF_INET6) {
 		len = pj_ansi_snprintf(p, end-p,
 				       ", IPv6 addr present\n");
 	    } else {
diff --git a/pjnath/src/pjnath/stun_session.c b/pjnath/src/pjnath/stun_session.c
index b4e7356..9bcff54 100644
--- a/pjnath/src/pjnath/stun_session.c
+++ b/pjnath/src/pjnath/stun_session.c
@@ -16,12 +16,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_session.h>
+#include <pjnath/stun_session.h>
 #include <pjlib.h>
 
 struct pj_stun_session
 {
-    pj_stun_endpoint	*endpt;
+    pj_stun_config	*cfg;
     pj_pool_t		*pool;
     pj_mutex_t		*mutex;
     pj_stun_session_cb	 cb;
@@ -119,7 +119,7 @@
     pj_stun_tx_data *tdata;
 
     /* Create pool and initialize basic tdata attributes */
-    pool = pj_pool_create(sess->endpt->pf, "tdata%p", 
+    pool = pj_pool_create(sess->cfg->pf, "tdata%p", 
 			  TDATA_POOL_SIZE, TDATA_POOL_INC, NULL);
     PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
 
@@ -170,7 +170,7 @@
 	tdata->client_tsx = NULL;
     }
     if (tdata->res_timer.id != PJ_FALSE) {
-	pj_timer_heap_cancel(tdata->sess->endpt->timer_heap, 
+	pj_timer_heap_cancel(tdata->sess->cfg->timer_heap, 
 			     &tdata->res_timer);
 	tdata->res_timer.id = PJ_FALSE;
 	pj_list_erase(tdata);
@@ -223,8 +223,8 @@
     pj_status_t status = 0;
 
     /* The server SHOULD include a SERVER attribute in all responses */
-    if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
-	PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type)) 
+    if (sess->srv_name.slen && (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
+			        PJ_STUN_IS_ERROR_RESPONSE(msg->hdr.type))) 
     {
 	pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SERVER,
 				    &sess->srv_name);
@@ -300,7 +300,7 @@
 
 /* **************************************************************************/
 
-PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
+PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_config *cfg,
 					    const char *name,
 					    const pj_stun_session_cb *cb,
 					    pj_bool_t fingerprint,
@@ -310,16 +310,16 @@
     pj_stun_session *sess;
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(endpt && cb && p_sess, PJ_EINVAL);
+    PJ_ASSERT_RETURN(cfg && cb && p_sess, PJ_EINVAL);
 
     if (name==NULL)
 	name = "sess%p";
 
-    pool = pj_pool_create(endpt->pf, name, 4000, 4000, NULL);
+    pool = pj_pool_create(cfg->pf, name, 4000, 4000, NULL);
     PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
 
     sess = PJ_POOL_ZALLOC_T(pool, pj_stun_session);
-    sess->endpt = endpt;
+    sess->cfg = cfg;
     sess->pool = pool;
     pj_memcpy(&sess->cb, cb, sizeof(*cb));
     sess->use_fingerprint = fingerprint;
@@ -383,8 +383,11 @@
 PJ_DEF(pj_status_t) pj_stun_session_set_server_name(pj_stun_session *sess,
 						    const pj_str_t *srv_name)
 {
-    PJ_ASSERT_RETURN(sess && srv_name, PJ_EINVAL);
-    pj_strdup(sess->pool, &sess->srv_name, srv_name);
+    PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+    if (srv_name)
+	pj_strdup(sess->pool, &sess->srv_name, srv_name);
+    else
+	sess->srv_name.slen = 0;
     return PJ_SUCCESS;
 }
 
@@ -489,14 +492,12 @@
     const pj_sockaddr *dst = (const pj_sockaddr*)addr;
     char buf[512];
     
-    if (dst->sa_family == PJ_AF_INET) {
-	const pj_sockaddr_in *dst4 = (const pj_sockaddr_in*)dst;
-	dst_name = pj_inet_ntoa(dst4->sin_addr);
-	dst_port = pj_ntohs(dst4->sin_port);
-    } else if (dst->sa_family == PJ_AF_INET6) {
-	const pj_sockaddr_in6 *dst6 = (const pj_sockaddr_in6*)dst;
+    if (dst->addr.sa_family == PJ_AF_INET) {
+	dst_name = pj_inet_ntoa(dst->ipv4.sin_addr);
+	dst_port = pj_ntohs(dst->ipv4.sin_port);
+    } else if (dst->addr.sa_family == PJ_AF_INET6) {
 	dst_name = "IPv6";
-	dst_port = pj_ntohs(dst6->sin6_port);
+	dst_port = pj_ntohs(dst->ipv6.sin6_port);
     } else {
 	LOG_ERR_(sess, "Invalid address family", PJ_EINVAL);
 	return;
@@ -558,7 +559,7 @@
     if (PJ_STUN_IS_REQUEST(tdata->msg->hdr.type)) {
 
 	/* Create STUN client transaction */
-	status = pj_stun_client_tsx_create(sess->endpt, tdata->pool, 
+	status = pj_stun_client_tsx_create(sess->cfg, tdata->pool, 
 					   &tsx_cb, &tdata->client_tsx);
 	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 	pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata);
@@ -592,10 +593,10 @@
 	    pj_timer_entry_init(&tdata->res_timer, PJ_TRUE, tdata, 
 				&on_cache_timeout);
 
-	    timeout.sec = sess->endpt->res_cache_msec / 1000;
-	    timeout.msec = sess->endpt->res_cache_msec % 1000;
+	    timeout.sec = sess->cfg->res_cache_msec / 1000;
+	    timeout.msec = sess->cfg->res_cache_msec % 1000;
 
-	    status = pj_timer_heap_schedule(sess->endpt->timer_heap, 
+	    status = pj_timer_heap_schedule(sess->cfg->timer_heap, 
 					    &tdata->res_timer,
 					    &timeout);
 	    if (status != PJ_SUCCESS) {
@@ -829,7 +830,7 @@
 
     PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL);
 
-    tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL);
+    tmp_pool = pj_pool_create(sess->cfg->pf, "tmpstun", 1024, 1024, NULL);
     if (!tmp_pool)
 	return PJ_ENOMEM;
 
diff --git a/pjnath/src/pjnath/stun_transaction.c b/pjnath/src/pjnath/stun_transaction.c
index 0000e3a..2813f7e 100644
--- a/pjnath/src/pjnath/stun_transaction.c
+++ b/pjnath/src/pjnath/stun_transaction.c
@@ -16,8 +16,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/stun_transaction.h>
-#include <pjlib-util/errno.h>
+#include <pjnath/stun_transaction.h>
+#include <pjnath/errno.h>
 #include <pj/assert.h>
 #include <pj/log.h>
 #include <pj/pool.h>
@@ -31,7 +31,7 @@
 struct pj_stun_client_tsx
 {
     char		 obj_name[PJ_MAX_OBJ_NAME];
-    pj_stun_endpoint	*endpt;
+    pj_stun_config	*cfg;
     pj_stun_tsx_cb	 cb;
     void		*user_data;
 
@@ -63,18 +63,18 @@
 /*
  * Create a STUN client transaction.
  */
-PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_endpoint *endpt,
+PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_config *cfg,
 					      pj_pool_t *pool,
 					      const pj_stun_tsx_cb *cb,
 					      pj_stun_client_tsx **p_tsx)
 {
     pj_stun_client_tsx *tsx;
 
-    PJ_ASSERT_RETURN(endpt && cb && p_tsx, PJ_EINVAL);
+    PJ_ASSERT_RETURN(cfg && cb && p_tsx, PJ_EINVAL);
     PJ_ASSERT_RETURN(cb->on_send_msg, PJ_EINVAL);
 
     tsx = PJ_POOL_ZALLOC_T(pool, pj_stun_client_tsx);
-    tsx->endpt = endpt;
+    tsx->cfg = cfg;
     pj_memcpy(&tsx->cb, cb, sizeof(*cb));
 
     tsx->timer.cb = &retransmit_timer_callback;
@@ -97,7 +97,7 @@
     PJ_ASSERT_RETURN(tsx, PJ_EINVAL);
 
     if (tsx->timer.id != 0) {
-	pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
+	pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->timer);
 	tsx->timer.id = 0;
     }
     return PJ_SUCCESS;
@@ -149,7 +149,7 @@
 	/* Calculate retransmit/timeout delay */
 	if (tsx->transmit_count == 0) {
 	    tsx->retransmit_time.sec = 0;
-	    tsx->retransmit_time.msec = tsx->endpt->rto_msec;
+	    tsx->retransmit_time.msec = tsx->cfg->rto_msec;
 
 	} else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT-1) {
 	    unsigned msec;
@@ -168,7 +168,7 @@
 	 * cancel it (as opposed to when schedule_timer() failed we cannot
 	 * cancel transmission).
 	 */;
-	status = pj_timer_heap_schedule(tsx->endpt->timer_heap, &tsx->timer,
+	status = pj_timer_heap_schedule(tsx->cfg->timer_heap, &tsx->timer,
 					&tsx->retransmit_time);
 	if (status != PJ_SUCCESS) {
 	    tsx->timer.id = 0;
@@ -182,7 +182,7 @@
     status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);
     if (status != PJ_SUCCESS) {
 	if (tsx->timer.id != 0) {
-	    pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
+	    pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->timer);
 	    tsx->timer.id = 0;
 	}
 	stun_perror(tsx, "STUN error sending message", status);
@@ -235,7 +235,7 @@
 	PJ_LOG(4,(tsx->obj_name, "STUN timeout waiting for response"));
 	tsx->complete = PJ_TRUE;
 	if (tsx->cb.on_complete) {
-	    tsx->cb.on_complete(tsx, PJLIB_UTIL_ESTUNNOTRESPOND, NULL);
+	    tsx->cb.on_complete(tsx, PJNATH_ESTUNNOTRESPOND, NULL);
 	}
 	return;
     }
@@ -268,7 +268,7 @@
     {
 	PJ_LOG(4,(tsx->obj_name, 
 		  "STUN rx_msg() error: not response message"));
-	return PJLIB_UTIL_ESTUNNOTRESPONSE;
+	return PJNATH_ESTUNNOTRESPONSE;
     }
 
 
@@ -276,7 +276,7 @@
      * We can cancel retransmit timer now.
      */
     if (tsx->timer.id) {
-	pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
+	pj_timer_heap_cancel(tsx->cfg->timer_heap, &tsx->timer);
 	tsx->timer.id = 0;
     }
 
@@ -300,7 +300,7 @@
     if (err_attr == NULL) {
 	status = PJ_SUCCESS;
     } else {
-	status = PJLIB_UTIL_ESTUNTSXFAILED;
+	status = PJNATH_ESTUNTSXFAILED;
     }
 
     /* Call callback */
diff --git a/pjnath/src/pjstun-client/client_main.c b/pjnath/src/pjstun-client/client_main.c
index be65b51..9bb249f 100644
--- a/pjnath/src/pjstun-client/client_main.c
+++ b/pjnath/src/pjstun-client/client_main.c
@@ -16,6 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
+#include <pjnath.h>
 #include <pjlib-util.h>
 #include <pjlib.h>
 
diff --git a/pjnath/src/pjstun-srv-test/bind_usage.c b/pjnath/src/pjstun-srv-test/bind_usage.c
index fc10fb9..3c1825f 100644
--- a/pjnath/src/pjstun-srv-test/bind_usage.c
+++ b/pjnath/src/pjstun-srv-test/bind_usage.c
@@ -85,7 +85,7 @@
     pj_bzero(&sess_cb, sizeof(sess_cb));
     sess_cb.on_send_msg = &sess_on_send_msg;
     sess_cb.on_rx_request = &sess_on_rx_request;
-    status = pj_stun_session_create(si->endpt, "bind%p", &sess_cb, PJ_FALSE,
+    status = pj_stun_session_create(si->cfg, "bind%p", &sess_cb, PJ_FALSE,
 				    &bu->session);
     if (status != PJ_SUCCESS) {
 	pj_stun_usage_destroy(bu->usage);
diff --git a/pjnath/src/pjstun-srv-test/server.c b/pjnath/src/pjstun-srv-test/server.c
index 5fdb233..d0fe426 100644
--- a/pjnath/src/pjstun-srv-test/server.c
+++ b/pjnath/src/pjstun-srv-test/server.c
@@ -83,8 +83,8 @@
     if (status != PJ_SUCCESS)
 	goto on_error;
 
-    status = pj_stun_endpoint_create(srv->si.pf, 0, srv->si.ioqueue, 
-				     srv->si.timer_heap, &srv->si.endpt);
+    status = pj_stun_config_create(srv->si.pf, 0, srv->si.ioqueue, 
+				     srv->si.timer_heap, &srv->si.cfg);
     if (status != PJ_SUCCESS)
 	goto on_error;
 
@@ -174,7 +174,7 @@
 	srv->threads[i] = NULL;
     }
 
-    pj_stun_endpoint_destroy(srv->si.endpt);
+    pj_stun_config_destroy(srv->si.cfg);
     pj_timer_heap_destroy(srv->si.timer_heap);
     pj_ioqueue_destroy(srv->si.ioqueue);
     pj_pool_release(srv->pool);
diff --git a/pjnath/src/pjstun-srv-test/server.h b/pjnath/src/pjstun-srv-test/server.h
index a88d87c..6c61da3 100644
--- a/pjnath/src/pjstun-srv-test/server.h
+++ b/pjnath/src/pjstun-srv-test/server.h
@@ -19,6 +19,7 @@
 #ifndef __STUN_SERVER_H__
 #define __STUN_SERVER_H__
 
+#include <pjnath.h>
 #include <pjlib-util.h>
 #include <pjlib.h>
 
@@ -30,7 +31,7 @@
 typedef struct pj_stun_server_info
 {
     pj_pool_factory	*pf;
-    pj_stun_endpoint	*endpt;
+    pj_stun_config	*cfg;
     pj_ioqueue_t	*ioqueue;
     pj_timer_heap_t	*timer_heap;
     unsigned		 thread_cnt;
diff --git a/pjnath/src/pjstun-srv-test/turn_usage.c b/pjnath/src/pjstun-srv-test/turn_usage.c
index e3d2e59..c1f83d1 100644
--- a/pjnath/src/pjstun-srv-test/turn_usage.c
+++ b/pjnath/src/pjstun-srv-test/turn_usage.c
@@ -69,7 +69,7 @@
 struct turn_usage
 {
     pj_pool_factory	*pf;
-    pj_stun_endpoint	*endpt;
+    pj_stun_config	*cfg;
     pj_ioqueue_t	*ioqueue;
     pj_timer_heap_t	*timer_heap;
     pj_pool_t		*pool;
@@ -165,7 +165,7 @@
     tu->pool = pool;
     tu->type = type;
     tu->pf = si->pf;
-    tu->endpt = si->endpt;
+    tu->cfg = si->cfg;
     tu->ioqueue = si->ioqueue;
     tu->timer_heap = si->timer_heap;
     tu->next_port = START_PORT;
@@ -197,7 +197,7 @@
     pj_bzero(&sess_cb, sizeof(sess_cb));
     sess_cb.on_send_msg = &tu_sess_on_send_msg;
     sess_cb.on_rx_request = &tu_sess_on_rx_request;
-    status = pj_stun_session_create(si->endpt, "turns%p", &sess_cb, PJ_FALSE,
+    status = pj_stun_session_create(si->cfg, "turns%p", &sess_cb, PJ_FALSE,
 				    &tu->default_session);
     if (status != PJ_SUCCESS) {
 	pj_stun_usage_destroy(tu->usage);
@@ -208,6 +208,8 @@
     sd->tu = tu;
     pj_stun_session_set_user_data(tu->default_session, sd);
 
+    pj_stun_session_set_server_name(tu->default_session, NULL);
+
     /* Create mutex */
     status = pj_mutex_create_recursive(pool, "turn%p", &tu->mutex);
     if (status != PJ_SUCCESS) {
@@ -620,7 +622,7 @@
     sess_cb.on_send_msg = &client_sess_on_send_msg;
     sess_cb.on_rx_request = &client_sess_on_rx_msg;
     sess_cb.on_rx_indication = &client_sess_on_rx_msg;
-    status = pj_stun_session_create(tu->endpt, client->obj_name, 
+    status = pj_stun_session_create(tu->cfg, client->obj_name, 
 				    &sess_cb, PJ_FALSE,
 				    &client->session);
     if (status != PJ_SUCCESS) {