Index: /pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h
===================================================================
--- /pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 1053)
+++ /pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 1054)
@@ -270,10 +270,10 @@
      * STUN/TURN Send Indication
      */
-    PJ_STUN_SEND_INDICATION		    = 0x0004,
+    PJ_STUN_SEND_INDICATION		    = 0x0014,
 
     /**
      * STUN/TURN Data Indication
      */
-    PJ_STUN_DATA_INDICATION		    = 0x0115,
+    PJ_STUN_DATA_INDICATION		    = 0x0015,
 
     /**
@@ -310,5 +310,5 @@
      * STUN/TURN Connect Status Indication
      */
-    PJ_STUN_CONNECT_STATUS_INDICATION	    = 0x0118
+    PJ_STUN_CONNECT_STATUS_INDICATION	    = 0x0018
 
 
@@ -516,5 +516,5 @@
    \endverbatim
  */
-typedef struct pj_stun_ip_addr_attr
+typedef struct pj_stun_sockaddr_attr
 {
     /**
@@ -522,4 +522,10 @@
      */
     pj_stun_attr_hdr	hdr;
+
+    /**
+     * Flag to indicate whether this attribute should be sent in XOR-ed
+     * format, or has been received in XOR-ed format.
+     */
+    pj_bool_t		xor_ed;
 
     /**
@@ -532,5 +538,5 @@
     } addr;
 
-} pj_stun_ip_addr_attr;
+} pj_stun_sockaddr_attr;
 
 
@@ -745,5 +751,5 @@
  * The MAPPED-ADDRESS attribute indicates the mapped transport address.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_mapped_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_mapped_addr_attr;
 
 
@@ -757,5 +763,5 @@
  * through NATs which would otherwise interfere with STUN.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_xor_mapped_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_xor_mapped_addr_attr;
 
 
@@ -777,5 +783,5 @@
  * MAPPED-ADDRESS.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_alt_server_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_alt_server_attr;
 
 
@@ -798,5 +804,5 @@
  * RFC 3489-bis standard.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_response_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_response_addr_attr;
 
 
@@ -813,5 +819,5 @@
  * RFC 3489-bis standard.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_changed_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_changed_addr_attr;
 
 
@@ -845,5 +851,5 @@
  * RFC 3489-bis standard.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_src_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_src_addr_attr;
 
 
@@ -857,5 +863,5 @@
  * denial-of-service attacks.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_reflected_from_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_reflected_from_attr;
 
 
@@ -902,5 +908,5 @@
  * from the STUN relay server.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_remote_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_remote_addr_attr;
 
 
@@ -920,5 +926,5 @@
  * address and port that the server allocated to the client.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_relay_addr_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_relay_addr_attr;
 
 
@@ -976,5 +982,5 @@
  * specific IP address be allocated to it.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_req_ip_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_req_ip_attr;
 
 /**
@@ -988,5 +994,5 @@
  * to XOR-MAPPED-ADDRESS.
  */
-typedef struct pj_stun_ip_addr_attr pj_stun_xor_reflected_from_attr;
+typedef struct pj_stun_sockaddr_attr pj_stun_xor_reflected_from_attr;
 
 /**
@@ -1016,5 +1022,5 @@
  * the STUN-aware NATs along the path.
  */
-typedef pj_stun_ip_addr_attr pj_stun_xor_internal_addr_attr;
+typedef pj_stun_sockaddr_attr pj_stun_xor_internal_addr_attr;
 
 /**
@@ -1305,10 +1311,10 @@
  * @return		PJ_SUCCESS on success or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_stun_ip_addr_attr_create(pj_pool_t *pool,
+PJ_DECL(pj_status_t) pj_stun_sockaddr_attr_create(pj_pool_t *pool,
 						int attr_type, 
 						pj_bool_t xor_ed,
 						const pj_sockaddr_t *addr,
 						unsigned addr_len,
-						pj_stun_ip_addr_attr **p_attr);
+						pj_stun_sockaddr_attr **p_attr);
 
 
@@ -1328,5 +1334,5 @@
  * @return		PJ_SUCCESS on success or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
+PJ_DECL(pj_status_t) pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
 						  pj_stun_msg *msg,
 						  int attr_type, 
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 1054)
@@ -90,8 +90,11 @@
 };
 
-static pj_status_t decode_ip_addr_attr(pj_pool_t *pool, 
+static pj_status_t decode_sockaddr_attr(pj_pool_t *pool, 
 				       const pj_uint8_t *buf, 
 				       void **p_attr);
-static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf, 
+static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool, 
+					      const pj_uint8_t *buf, 
+					      void **p_attr);
+static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf, 
 				       unsigned len, 
 				       unsigned *printed);
@@ -144,12 +147,12 @@
 	/* PJ_STUN_ATTR_MAPPED_ADDR, */
 	"MAPPED-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
 	/* PJ_STUN_ATTR_RESPONSE_ADDR, */
 	"RESPONSE-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -162,12 +165,12 @@
 	/* PJ_STUN_ATTR_SOURCE_ADDR, */
 	"SOURCE-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
 	/* PJ_STUN_ATTR_CHANGED_ADDR, */
 	"CHANGED-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -204,6 +207,6 @@
 	/* PJ_STUN_ATTR_REFLECTED_FROM, */
 	"REFLECTED-FROM",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -246,6 +249,6 @@
 	/* PJ_STUN_ATTR_REMOTE_ADDRESS, */
 	"REMOTE-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -270,6 +273,6 @@
 	/* PJ_STUN_ATTR_RELAY_ADDRESS, */
 	"RELAY-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -330,6 +333,6 @@
 	/* PJ_STUN_ATTR_XOR_MAPPED_ADDRESS, */
 	"XOR-MAPPED-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_xored_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -342,12 +345,12 @@
 	/* PJ_STUN_ATTR_REQUESTED_IP, */
 	"REQUESTED-IP",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
 	/* PJ_STUN_ATTR_XOR_REFLECTED_FROM, */
 	"XOR-REFLECTED-FROM",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_xored_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -366,6 +369,6 @@
 	/* PJ_STUN_ATTR_XOR_INTERNAL_ADDR, */
 	"XOR-INTERNAL-ADDRESS",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_xored_sockaddr_attr,
+	&encode_sockaddr_attr
     },
 
@@ -396,6 +399,6 @@
 	/* PJ_STUN_ATTR_ALTERNATE_SERVER, */
 	"ALTERNATE-SERVER",
-	&decode_ip_addr_attr,
-	&encode_ip_addr_attr
+	&decode_sockaddr_attr,
+	&encode_sockaddr_attr
     },
     {
@@ -540,12 +543,12 @@
  */
 PJ_DEF(pj_status_t) 
-pj_stun_ip_addr_attr_create(pj_pool_t *pool,
-			    int attr_type,
-			    pj_bool_t xor_ed,
-			    const pj_sockaddr_t *addr,
-			    unsigned addr_len,
-			    pj_stun_ip_addr_attr **p_attr)
-{
-    pj_stun_ip_addr_attr *attr;
+pj_stun_sockaddr_attr_create(pj_pool_t *pool,
+			     int attr_type,
+			     pj_bool_t xor_ed,
+			     const pj_sockaddr_t *addr,
+			     unsigned addr_len,
+			     pj_stun_sockaddr_attr **p_attr)
+{
+    pj_stun_sockaddr_attr *attr;
 
     PJ_ASSERT_RETURN(pool && addr_len && addr && p_attr, PJ_EINVAL);
@@ -553,21 +556,9 @@
 		     addr_len == sizeof(pj_sockaddr_in6), PJ_EINVAL);
 
-    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
     INIT_ATTR(attr, attr_type, STUN_GENERIC_IP_ADDR_LEN);
 
-    if (!xor_ed) {
-	pj_memcpy(&attr->addr, addr, addr_len);
-    } else if (addr_len == sizeof(pj_sockaddr_in)) {
-	const pj_sockaddr_in *addr4 = (const pj_sockaddr_in*) addr;
-
-	pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
-	attr->addr.ipv4.sin_port = (pj_uint16_t)(addr4->sin_port ^ 0x2112);
-	attr->addr.ipv4.sin_addr.s_addr = (addr4->sin_addr.s_addr ^ 
-					   pj_htonl(0x2112A442));
-    } else if (addr_len == sizeof(pj_sockaddr_in6)) {
-	return PJLIB_UTIL_ESTUNIPV6NOTSUPP;
-    } else {
-	return PJLIB_UTIL_ESTUNINADDRLEN;
-    }
+    pj_memcpy(&attr->addr, addr, addr_len);
+    attr->xor_ed = xor_ed;
 
     *p_attr = attr;
@@ -581,15 +572,15 @@
  */
 PJ_DEF(pj_status_t) 
-pj_stun_msg_add_ip_addr_attr(pj_pool_t *pool,
-			     pj_stun_msg *msg,
-			     int attr_type, 
-			     pj_bool_t xor_ed,
-			     const pj_sockaddr_t *addr,
-			     unsigned addr_len)
-{
-    pj_stun_ip_addr_attr *attr;
+pj_stun_msg_add_sockaddr_attr(pj_pool_t *pool,
+			      pj_stun_msg *msg,
+			      int attr_type, 
+			      pj_bool_t xor_ed,
+			      const pj_sockaddr_t *addr,
+			      unsigned addr_len)
+{
+    pj_stun_sockaddr_attr *attr;
     pj_status_t status;
 
-    status = pj_stun_ip_addr_attr_create(pool, attr_type, xor_ed,
+    status = pj_stun_sockaddr_attr_create(pool, attr_type, xor_ed,
 					         addr, addr_len, &attr);
     if (status != PJ_SUCCESS)
@@ -599,13 +590,13 @@
 }
 
-static pj_status_t decode_ip_addr_attr(pj_pool_t *pool, 
-				       const pj_uint8_t *buf, 
-				       void **p_attr)
-{
-    pj_stun_ip_addr_attr *attr;
+static pj_status_t decode_sockaddr_attr(pj_pool_t *pool, 
+				        const pj_uint8_t *buf, 
+				        void **p_attr)
+{
+    pj_stun_sockaddr_attr *attr;
     pj_uint32_t val;
 
     /* Create the attribute */
-    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_ip_addr_attr);
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
     pj_memcpy(attr, buf, ATTR_HDR_LEN);
 
@@ -627,5 +618,5 @@
     /* Get port and address */
     pj_sockaddr_in_init(&attr->addr.ipv4, NULL, 0);
-    attr->addr.ipv4.sin_port = getval16(buf, ATTR_HDR_LEN + 2);
+    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);
 
@@ -637,6 +628,47 @@
 
 
-static pj_status_t encode_ip_addr_attr(const void *a, pj_uint8_t *buf, 
-				       unsigned len, unsigned *printed)
+static pj_status_t decode_xored_sockaddr_attr(pj_pool_t *pool, 
+					      const pj_uint8_t *buf, 
+					      void **p_attr)
+{
+    pj_stun_sockaddr_attr *attr;
+    pj_uint32_t val;
+
+    /* Create the attribute */
+    attr = PJ_POOL_ZALLOC_T(pool, pj_stun_sockaddr_attr);
+    pj_memcpy(attr, buf, ATTR_HDR_LEN);
+
+    /* Convert to host byte order */
+    attr->hdr.type = pj_ntohs(attr->hdr.type);
+    attr->hdr.length = pj_ntohs(attr->hdr.length);
+
+    /* Check that the attribute length is valid */
+    if (attr->hdr.length != STUN_GENERIC_IP_ADDR_LEN)
+	return PJLIB_UTIL_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;
+
+    /* 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);
+
+    attr->addr.ipv4.sin_port ^= 0x2112;
+    attr->addr.ipv4.sin_addr.s_addr ^= pj_htonl(0x2112A442);
+
+    /* Done */
+    *p_attr = attr;
+
+    return PJ_SUCCESS;
+}
+
+
+static pj_status_t encode_sockaddr_attr(const void *a, pj_uint8_t *buf, 
+				        unsigned len, unsigned *printed)
 {
     enum {
@@ -644,7 +676,7 @@
     };
     pj_uint8_t *start_buf = buf;
-    const pj_stun_ip_addr_attr *ca = 
-	(const pj_stun_ip_addr_attr *)a;
-    pj_stun_ip_addr_attr *attr;
+    const pj_stun_sockaddr_attr *ca = 
+	(const pj_stun_sockaddr_attr *)a;
+    pj_stun_sockaddr_attr *attr;
 
     if (len < ATTR_LEN) 
@@ -653,5 +685,5 @@
     /* Copy and convert headers to network byte order */
     pj_memcpy(buf, a, ATTR_HDR_LEN);
-    attr = (pj_stun_ip_addr_attr*) buf;
+    attr = (pj_stun_sockaddr_attr*) buf;
     attr->hdr.type = pj_htons(attr->hdr.type);
     attr->hdr.length = pj_htons((pj_uint16_t)STUN_GENERIC_IP_ADDR_LEN);
@@ -665,11 +697,31 @@
     *buf++ = 1;
 
-    /* Port */
-    pj_memcpy(buf, &ca->addr.ipv4.sin_port, 2);
-    buf += 2;
-
-    /* Address */
-    pj_memcpy(buf, &ca->addr.ipv4.sin_addr, 4);
-    buf += 4;
+    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;
+
+	port ^= 0x2112;
+	addr ^= pj_htonl(0x2112A442);
+
+	/* Port */
+	pj_memcpy(buf, &port, 2);
+	buf += 2;
+
+	/* Address */
+	pj_memcpy(buf, &addr, 4);
+	buf += 4;
+
+    } else {
+	/* Port */
+	pj_memcpy(buf, &ca->addr.ipv4.sin_port, 2);
+	buf += 2;
+
+	/* Address */
+	pj_memcpy(buf, &ca->addr.ipv4.sin_addr, 4);
+	buf += 4;
+    }
 
     pj_assert(buf - start_buf == ATTR_LEN);
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 1054)
@@ -77,7 +77,7 @@
     case PJ_STUN_ATTR_ALTERNATE_SERVER:
 	{
-	    const pj_stun_ip_addr_attr *attr;
-
-	    attr = (const pj_stun_ip_addr_attr*)ahdr;
+	    const pj_stun_sockaddr_attr *attr;
+
+	    attr = (const pj_stun_sockaddr_attr*)ahdr;
 
 	    if (attr->addr.addr.sa_family == PJ_AF_INET) {
Index: /pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 1054)
@@ -22,6 +22,7 @@
 
 #define THIS_FILE	"client_main.c"
+#define LOCAL_PORT	1998
 #define BANDWIDTH	64		    /* -1 to disable */
-#define LIFETIME	30		    /* -1 to disable */
+#define LIFETIME	600		    /* -1 to disable */
 #define REQ_TRANSPORT	-1		    /* 0: udp, 1: tcp, -1: disable */
 #define REQ_PORT_PROPS	-1		    /* -1 to disable */
@@ -40,6 +41,8 @@
     pj_bool_t		 quit;
     pj_sockaddr_in	 peer_addr;
-    pj_sockaddr_in	 srv_addr;  /**< server addr */
-
+    pj_sockaddr_in	 srv_addr;
+    pj_sockaddr_in	 relay_addr;
+    char		 data_buf[256];
+    char		*data;
 } g;
 
@@ -52,6 +55,10 @@
     char    *password;
     char    *nonce;
+    char    *peer_addr;
     pj_bool_t use_fingerprint;
 } o;
+
+
+static pj_status_t parse_addr(const char *input, pj_sockaddr_in *addr);
 
 
@@ -88,5 +95,24 @@
 {
     if (status == PJ_SUCCESS) {
-	puts("Client transaction completes");
+	switch (response->hdr.type) {
+	case PJ_STUN_ALLOCATE_RESPONSE:
+	    {
+		pj_stun_relay_addr_attr *ar;
+
+		ar = (pj_stun_relay_addr_attr*)
+		     pj_stun_msg_find_attr(response, 
+					   PJ_STUN_ATTR_RELAY_ADDR, 0);
+		if (ar) {
+		    pj_memcpy(&g.relay_addr, &ar->addr.ipv4,
+			      sizeof(pj_sockaddr_in));
+		    PJ_LOG(3,(THIS_FILE, "Relay address is %s:%d",
+			      pj_inet_ntoa(g.relay_addr.sin_addr),
+			      (int)pj_ntohs(g.relay_addr.sin_port)));
+		} else {
+		    pj_memset(&g.relay_addr, 0, sizeof(g.relay_addr));
+		}
+	    }
+	    break;
+	}
     } else {
 	my_perror("Client transaction error", status);
@@ -120,10 +146,17 @@
 		addrlen = sizeof(addr);
 		rc = pj_sock_recvfrom(g.sock, buffer, &len, 0, &addr, &addrlen);
-		if (rc == PJ_SUCCESS && len > 0) {
+		if (rc != PJ_SUCCESS || len <= 0)
+		    continue;
+
+		if (pj_stun_msg_check(buffer, len, PJ_STUN_IS_DATAGRAM)==PJ_SUCCESS) {
 		    rc = pj_stun_session_on_rx_pkt(g.sess, buffer, len, 
-						   PJ_STUN_IS_DATAGRAM|PJ_STUN_CHECK_PACKET, 
+						   0, 
 						   NULL, &addr, addrlen);
 		    if (rc != PJ_SUCCESS)
 			my_perror("Error processing packet", rc);
+
+		} else {
+		    buffer[len] = '\0';
+		    PJ_LOG(3,(THIS_FILE, "Received data: %s", (char*)buffer));
 		}
 	    }
@@ -139,4 +172,5 @@
     pj_sockaddr_in addr;
     pj_stun_session_cb stun_cb;
+    int len;
     pj_status_t status;
 
@@ -182,4 +216,18 @@
     status = pj_sockaddr_in_init(&addr, NULL, 0);
     pj_assert(status == PJ_SUCCESS);
+
+    addr.sin_port = pj_htons((pj_uint16_t)LOCAL_PORT);
+    status = pj_sock_bind(g.sock, &addr, sizeof(addr));
+    pj_assert(status == PJ_SUCCESS);
+
+    len = sizeof(addr);
+    status = pj_sock_getsockname(g.sock, &addr, &len);
+    pj_assert(status == PJ_SUCCESS);
+
+    PJ_LOG(3,(THIS_FILE, "Listening on port %d", (int)pj_ntohs(addr.sin_port)));
+
+    pj_memcpy(&g.peer_addr, &addr, sizeof(pj_sockaddr_in));
+    if (g.peer_addr.sin_addr.s_addr == 0)
+	pj_gethostip(&g.peer_addr.sin_addr);
 
     pj_memset(&stun_cb, 0, sizeof(stun_cb));
@@ -207,4 +255,9 @@
     } else {
 	puts("Credential not set");
+    }
+
+    if (o.peer_addr) {
+	if (parse_addr(o.peer_addr, &g.peer_addr)!=PJ_SUCCESS)
+	    return -1;
     }
 
@@ -297,5 +350,5 @@
 
 	    pj_sockaddr_in_init(&addr, pj_cstr(&tmp, REQ_IP), 0);
-	    pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+	    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
 					 PJ_STUN_ATTR_REQ_IP, PJ_FALSE,
 					 &addr, sizeof(addr));
@@ -321,9 +374,9 @@
     }
 
-    rc = pj_stun_session_create_req(g.sess, PJ_STUN_ALLOCATE_REQUEST, &tdata);
+    rc = pj_stun_session_create_req(g.sess, PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST, &tdata);
     pj_assert(rc == PJ_SUCCESS);
 
     if (set) {
-	pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
+	pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
 				     PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
 				     &g.peer_addr, sizeof(g.peer_addr));
@@ -338,16 +391,115 @@
 static void send_send_ind(void)
 {
-}
-
-static void send_raw_data(void)
-{
+    pj_stun_tx_data *tdata;
+    int len;
+    pj_status_t rc;
+
+    if (g.peer_addr.sin_addr.s_addr == 0 ||
+	g.peer_addr.sin_port == 0)
+    {
+	puts("Error: peer address is not set");
+	return;
+    }
+
+    len = strlen(g.data);
+    if (len==0) {
+	puts("Error: data is not set");
+	return;
+    }
+
+    rc = pj_stun_session_create_ind(g.sess, PJ_STUN_SEND_INDICATION, &tdata);
+    pj_assert(rc == PJ_SUCCESS);
+
+    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+				  PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
+				  &g.peer_addr, sizeof(g.peer_addr));
+    pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
+				PJ_STUN_ATTR_DATA, g.data, len);
+
+    rc = pj_stun_session_send_msg(g.sess, PJ_FALSE, 
+				  &g.srv_addr, sizeof(g.srv_addr),
+				  tdata);
+    pj_assert(rc == PJ_SUCCESS);
+
+}
+
+static void send_raw_data_to_srv(void)
+{
+    pj_ssize_t len;
+
+    if (g.srv_addr.sin_addr.s_addr == 0 ||
+	g.srv_addr.sin_port == 0)
+    {
+	puts("Error: server address is not set");
+	return;
+    }
+
+    len = strlen(g.data);
+    if (len==0) {
+	puts("Error: data is not set");
+	return;
+    }
+
+    len = strlen(g.data);
+    pj_sock_sendto(g.sock, g.data, &len, 0, &g.srv_addr, sizeof(g.srv_addr));
+}
+
+static void send_raw_data_to_relay(void)
+{
+    pj_ssize_t len;
+
+    if (g.relay_addr.sin_addr.s_addr == 0 ||
+	g.relay_addr.sin_port == 0)
+    {
+	puts("Error: relay address is not set");
+	return;
+    }
+
+    len = strlen(g.data);
+    if (len==0) {
+	puts("Error: data is not set");
+	return;
+    }
+
+    len = strlen(g.data);
+    pj_sock_sendto(g.sock, g.data, &len, 0, &g.relay_addr, sizeof(g.relay_addr));
+}
+
+static pj_status_t parse_addr(const char *input,
+			      pj_sockaddr_in *addr)
+{
+    const char *pos;
+    pj_str_t ip;
+    pj_uint16_t port;
+    pj_sockaddr_in tmp_addr;
+
+    pos = pj_ansi_strchr(input, ':');
+    if (pos==NULL) {
+	puts("Invalid format");
+	return -1;
+    }
+
+    ip.ptr = (char*)input;
+    ip.slen = pos - input;
+    port = (pj_uint16_t)atoi(pos+1);
+
+    if (port==0) {
+	puts("Invalid port");
+	return -1;
+    }
+
+    if (pj_sockaddr_in_init(&tmp_addr, &ip, port)!=PJ_SUCCESS) {
+	puts("Invalid address");
+	return -1;
+    }
+
+    pj_memcpy(addr, &tmp_addr, sizeof(tmp_addr));
+
+    return PJ_SUCCESS;
 }
 
 static void set_peer_addr(void)
 {
-    char ip_addr[64];
-    pj_str_t tmp;
-    pj_sockaddr_in addr;
-    int port;
+    char addr[64];
 
     printf("Current peer address: %s:%d\n", 
@@ -357,16 +509,10 @@
     printf("Input peer address in IP:PORT format: ");
     fflush(stdout);
-
-    if (scanf("%s:%d", ip_addr, &port) != 2) {
-	puts("Error.");
-	return;
-    }
-
-    if (pj_sockaddr_in_init(&addr, pj_cstr(&tmp,ip_addr), (pj_uint16_t)port) != PJ_SUCCESS) {
-	puts("Error: invalid address");
-	return;
-    }
-
-    g.peer_addr = addr;
+    gets(addr);
+
+    if (parse_addr(addr, &g.peer_addr) != PJ_SUCCESS) {
+	return;
+    }
+
 }
 
@@ -376,12 +522,13 @@
     printf("  pr      Set peer address (currently %s:%d)\n",
 	   pj_inet_ntoa(g.peer_addr.sin_addr), pj_ntohs(g.peer_addr.sin_port));
-    puts("");
+    printf("  dt      Set data (currently \"%s\")\n", g.data);
     puts("  br      Send Bind request");
     puts("  ar      Send Allocate request");
     puts("  dr      Send de-Allocate request");
-    puts("  sr      Send Set Active Indication request");
-    puts("  cr      Send clear Active Indication request");
+    puts("  sr      Send Set Active Destination request");
+    puts("  cr      Send clear Active Destination request");
     puts("  si      Send data with Send Indication");
-    puts("  rw      Send raw data");
+    puts("  rw      Send raw data to TURN server");
+    puts("  rW      Send raw data to relay address");
     puts("  q       Quit");
     puts("");
@@ -399,5 +546,14 @@
 	fgets(input, sizeof(input), stdin);
 	
-	if (input[0]=='b' && input[1]=='r') {
+	if (0) {
+
+	} else if (input[0]=='d' && input[1]=='t') {
+	    printf("Input data: ");
+	    gets(g.data);
+	    
+	} else if (input[0]=='p' && input[1]=='r') {
+	    set_peer_addr();
+	    
+	} else if (input[0]=='b' && input[1]=='r') {
 	    send_bind_request();
 	    
@@ -418,8 +574,8 @@
 	    
 	} else if (input[0]=='r' && input[1]=='w') {
-	    send_raw_data();
-	    
-	} else if (input[0]=='p' && input[1]=='r') {
-	    set_peer_addr();
+	    send_raw_data_to_srv();
+	    
+	} else if (input[0]=='r' && input[1]=='W') {
+	    send_raw_data_to_relay();
 	    
 	} else if (input[0]=='q') {
@@ -442,4 +598,6 @@
     puts(" --nonce, -N       Set NONCE");   
     puts(" --fingerprint, -F Use fingerprint for outgoing requests");
+    puts(" --peer, -P        Set peer address (address is in HOST:PORT format)");
+    puts(" --data, -D        Set data");
     puts(" --help, -h");
 }
@@ -453,4 +611,6 @@
 	{ "nonce",	1, 0, 'N'},
 	{ "fingerprint",0, 0, 'F'},
+	{ "peer",	1, 0, 'P'},
+	{ "data",	1, 0, 'D'},
 	{ "help",	0, 0, 'h'}
     };
@@ -459,4 +619,6 @@
     pj_status_t status;
 
+    g.data = g.data_buf;
+
     while((c=pj_getopt_long(argc,argv, "r:u:p:hF", long_options, &opt_id))!=-1) {
 	switch (c) {
@@ -479,4 +641,11 @@
 	    o.use_fingerprint = PJ_TRUE;
 	    break;
+	case 'P':
+	    o.peer_addr = pj_optarg;
+	    break;
+	case 'D':
+	    g.data = pj_optarg;
+	    break;
+
 	default:
 	    printf("Argument \"%s\" is not valid. Use -h to see help",
Index: /pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-srv-test/bind_usage.c	(revision 1054)
@@ -163,8 +163,8 @@
 
     /* Create MAPPED-ADDRESS attribute */
-    status = pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
-				   	  PJ_STUN_ATTR_MAPPED_ADDR,
-					  PJ_FALSE,
-				          src_addr, src_addr_len);
+    status = pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+				   	   PJ_STUN_ATTR_MAPPED_ADDR,
+					   PJ_FALSE,
+				           src_addr, src_addr_len);
     if (status != PJ_SUCCESS) {
 	pj_stun_perror(THIS_FILE, "Error creating response", status);
@@ -176,8 +176,8 @@
     if (msg->hdr.magic == PJ_STUN_MAGIC) {
 	status = 
-	    pj_stun_msg_add_ip_addr_attr(tdata->pool, tdata->msg,
-					 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
-					 PJ_TRUE,
-					 src_addr, src_addr_len);
+	    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+					  PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+					  PJ_TRUE,
+					  src_addr, src_addr_len);
 	if (status != PJ_SUCCESS) {
 	    pj_stun_perror(THIS_FILE, "Error creating response", status);
Index: /pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-srv-test/main.c	(revision 1054)
@@ -123,5 +123,14 @@
     }
 
+    /*
     status = pj_stun_bind_usage_create(srv, NULL, 3478, NULL);
+    if (status != PJ_SUCCESS) {
+	pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
+	return 1;
+    }
+    */
+
+    status = pj_stun_turn_usage_create(srv, PJ_SOCK_DGRAM, NULL,
+				       3478, NULL);
     if (status != PJ_SUCCESS) {
 	pj_stun_perror(THIS_FILE, "Unable to create bind usage", status);
Index: /pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-srv-test/server.h	(revision 1054)
@@ -113,9 +113,14 @@
 					  unsigned addr_len);
 
-PJ_DEF(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
-					      const pj_str_t *ip_addr,
-					      unsigned port,
-					      pj_stun_usage **p_bu);
+PJ_DECL(pj_status_t) pj_stun_bind_usage_create(pj_stun_server *srv,
+					       const pj_str_t *ip_addr,
+					       unsigned port,
+					       pj_stun_usage **p_bu);
 
+PJ_DECL(pj_status_t) pj_stun_turn_usage_create(pj_stun_server *srv,
+					       int type,
+					       const pj_str_t *ip_addr,
+					       unsigned port,
+					       pj_stun_usage **p_bu);
 
 
Index: /pjproject/trunk/pjlib-util/src/pjstun-srv-test/turn_usage.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-srv-test/turn_usage.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-srv-test/turn_usage.c	(revision 1054)
@@ -50,4 +50,9 @@
 					 unsigned src_addr_len);
 
+static pj_status_t handle_binding_req(pj_stun_session *session,
+				      const pj_stun_msg *msg,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len);
+
 static pj_status_t client_create(struct turn_usage *tu,
 				 const pj_sockaddr_t *src_addr,
@@ -91,9 +96,11 @@
     pj_mutex_t		*mutex;
 
+    pj_sockaddr_in	 client_src_addr;
+
     /* Socket and socket address of the allocated port */
     int			 sock_type;
     pj_sock_t		 sock;
     pj_ioqueue_key_t	*key;
-    pj_sockaddr_in	 client_addr;
+    pj_sockaddr_in	 alloc_addr;
 
     /* Allocation properties */
@@ -150,6 +157,6 @@
     pj_status_t status;
 
-    PJ_ASSERT_RETURN(srv && (type==PJ_SOCK_DGRAM||type==PJ_SOCK_STREAM) &&
-		     p_bu, PJ_EINVAL);
+    PJ_ASSERT_RETURN(srv && (type==PJ_SOCK_DGRAM||type==PJ_SOCK_STREAM),
+		     PJ_EINVAL);
     si = pj_stun_server_get_info(srv);
 
@@ -160,6 +167,9 @@
     tu->pf = si->pf;
     tu->endpt = si->endpt;
+    tu->ioqueue = si->ioqueue;
     tu->timer_heap = si->timer_heap;
     tu->next_port = START_PORT;
+    tu->max_bw_kbps = 64;
+    tu->max_lifetime = 10 * 60;
 
     status = pj_sockaddr_in_init(&local_addr, ip_addr, (pj_uint16_t)port);
@@ -206,5 +216,7 @@
     }
 
-    *p_bu = tu->usage;
+    if (p_bu) {
+	*p_bu = tu->usage;
+    }
 
     return PJ_SUCCESS;
@@ -224,12 +236,14 @@
 
     /* Destroy all clients */
-    it = pj_hash_first(tu->client_htable, &hit);
-    while (it) {
-	struct turn_client *client;
-
-	client = (struct turn_client *)pj_hash_this(tu->client_htable, it);
-	client_destroy(client, PJ_SUCCESS);
-
-	it = pj_hash_next(tu->client_htable, it);
+    if (tu->client_htable) {
+	it = pj_hash_first(tu->client_htable, &hit);
+	while (it) {
+	    struct turn_client *client;
+
+	    client = (struct turn_client *)pj_hash_this(tu->client_htable, it);
+	    client_destroy(client, PJ_SUCCESS);
+
+	    it = pj_hash_first(tu->client_htable, &hit);
+	}
     }
 
@@ -392,4 +406,5 @@
 	}
 
+	*p_sock = sock;
 	return PJ_SUCCESS;
     }
@@ -420,5 +435,8 @@
     pj_assert(sd->client == NULL);
 
-    if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
+    if (msg->hdr.type == PJ_STUN_BINDING_REQUEST) {
+	return handle_binding_req(sess, msg, src_addr, src_addr_len);
+
+    } else if (msg->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
 	if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
 	    status = pj_stun_session_create_response(sess, msg, 
@@ -506,7 +524,7 @@
 static const char *get_tp_type(int type)
 {
-    if (type==0)
+    if (type==PJ_SOCK_DGRAM)
 	return "udp";
-    else if (type==1)
+    else if (type==PJ_SOCK_STREAM)
 	return "tcp";
     else
@@ -520,10 +538,10 @@
  * the packet is handed over to the client.
  */
-static pj_status_t client_sess_on_rx_request(pj_stun_session *sess,
-					     const pj_uint8_t *pkt,
-					     unsigned pkt_len,
-					     const pj_stun_msg *msg,
-					     const pj_sockaddr_t *src_addr,
-					     unsigned src_addr_len)
+static pj_status_t client_sess_on_rx_msg(pj_stun_session *sess,
+					 const pj_uint8_t *pkt,
+					 unsigned pkt_len,
+					 const pj_stun_msg *msg,
+					 const pj_sockaddr_t *src_addr,
+					 unsigned src_addr_len)
 {
     struct session_data *sd;
@@ -577,4 +595,6 @@
     pj_status_t status;
 
+    PJ_ASSERT_RETURN(src_addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
+
     pool = pj_pool_create(tu->pf, "turnc%p", 4000, 4000, NULL);
     client = PJ_POOL_ZALLOC_T(pool, struct turn_client);
@@ -582,4 +602,7 @@
     client->tu = tu;
     client->sock = PJ_INVALID_SOCKET;
+
+    pj_memcpy(&client->client_src_addr, src_addr,
+	      sizeof(client->client_src_addr));
 
     if (src_addr) {
@@ -596,5 +619,6 @@
     pj_bzero(&sess_cb, sizeof(sess_cb));
     sess_cb.on_send_msg = &client_sess_on_send_msg;
-    sess_cb.on_rx_request = &client_sess_on_rx_request;
+    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, 
 				    &sess_cb, PJ_FALSE,
@@ -668,5 +692,6 @@
     pj_mutex_lock(tu->mutex);
     pj_hash_set(NULL, tu->client_htable, 
-		&client->client_addr, sizeof(client->client_addr), 0, NULL);
+		&client->client_src_addr, sizeof(client->client_src_addr), 
+		0, NULL);
     pj_mutex_unlock(tu->mutex);
 
@@ -710,5 +735,5 @@
     /* Update address */
     addrlen = sizeof(pj_sockaddr_in);
-    status = pj_sock_getsockname(client->sock, &client->client_addr, 
+    status = pj_sock_getsockname(client->sock, &client->alloc_addr, 
 			         &addrlen);
     if (status != PJ_SUCCESS) {
@@ -716,4 +741,13 @@
 	client->sock = PJ_INVALID_SOCKET;
 	return status;
+    }
+
+    if (client->alloc_addr.sin_addr.s_addr == 0) {
+	status = pj_gethostip(&client->alloc_addr.sin_addr);
+	if (status != PJ_SUCCESS) {
+	    pj_sock_close(client->sock);
+	    client->sock = PJ_INVALID_SOCKET;
+	    return status;
+	}
     }
 
@@ -741,6 +775,6 @@
 	      client->obj_name,
 	      get_tp_type(client->sock_type),
-	      pj_inet_ntoa(client->client_addr.sin_addr),
-	      (int)pj_ntohs(client->client_addr.sin_port)));
+	      pj_inet_ntoa(client->alloc_addr.sin_addr),
+	      (int)pj_ntohs(client->alloc_addr.sin_port)));
 
     return PJ_SUCCESS;
@@ -767,6 +801,6 @@
 	      client->obj_name,
 	      get_tp_type(client->sock_type),
-	      pj_inet_ntoa(client->client_addr.sin_addr),
-	      (int)pj_ntohs(client->client_addr.sin_port)));
+	      pj_inet_ntoa(client->alloc_addr.sin_addr),
+	      (int)pj_ntohs(client->alloc_addr.sin_port)));
     return PJ_SUCCESS;
 }
@@ -796,13 +830,13 @@
     peer = PJ_POOL_ZALLOC_T(client->pool, struct peer);
     peer->client = client;
-    pj_memcpy(&peer->addr, peer_addr, sizeof(*peer_addr));
+    pj_memcpy(&peer->addr, peer_addr, sizeof(peer->addr));
 
     pj_hash_set(client->pool, client->peer_htable,
-		peer_addr, sizeof(*peer_addr), hval, peer);
+		&peer->addr, sizeof(peer->addr), hval, peer);
 
     PJ_LOG(4,(THIS_FILE, "TURN client %s: peer %s:%s:%d added",
 	      client->obj_name, get_tp_type(client->sock_type), 
-	      pj_inet_ntoa(peer_addr->sin_addr),
-	      (int)pj_ntohs(peer_addr->sin_port)));
+	      pj_inet_ntoa(peer->addr.sin_addr),
+	      (int)pj_ntohs(peer->addr.sin_port)));
 
     return peer;
@@ -976,5 +1010,5 @@
     timeout.msec = 0;
     pj_timer_heap_schedule(client->tu->timer_heap, &client->expiry_timer, &timeout);
-
+    client->expiry_timer.id = PJ_TRUE;
 
     /* Done successfully, create and send success response */
@@ -989,8 +1023,8 @@
     pj_stun_msg_add_uint_attr(response->pool, response->msg,
 			      PJ_STUN_ATTR_LIFETIME, client->lifetime);
-    pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+    pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
 				 PJ_STUN_ATTR_MAPPED_ADDR, PJ_FALSE,
 				 src_addr, src_addr_len);
-    pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+    pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
 				 PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
 				 src_addr, src_addr_len);
@@ -998,7 +1032,7 @@
     addr_len = sizeof(req_addr);
     pj_sock_getsockname(client->sock, &req_addr, &addr_len);
-    pj_stun_msg_add_ip_addr_attr(response->pool, response->msg,
+    pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
 				 PJ_STUN_ATTR_RELAY_ADDR, PJ_FALSE,
-				 &req_addr, addr_len);
+				 &client->alloc_addr, addr_len);
 
     PJ_LOG(4,(THIS_FILE, "TURN client %s: relay allocated or refreshed, "
@@ -1011,4 +1045,44 @@
     return pj_stun_session_send_msg(client->session, PJ_TRUE, 
 				    src_addr, src_addr_len, response);
+}
+
+
+/*
+ * Handle incoming Binding request.
+ * This function is called by client_handle_stun_msg() below.
+ */
+static pj_status_t handle_binding_req(pj_stun_session *session,
+				      const pj_stun_msg *msg,
+				      const pj_sockaddr_t *src_addr,
+				      unsigned src_addr_len)
+{
+    pj_stun_tx_data *tdata;
+    pj_status_t status;
+
+    /* Create response */
+    status = pj_stun_session_create_response(session, msg, 0, NULL, 
+					     &tdata);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Create MAPPED-ADDRESS attribute */
+    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+				 PJ_STUN_ATTR_MAPPED_ADDR,
+				PJ_FALSE,
+				src_addr, src_addr_len);
+
+    /* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
+    if (msg->hdr.magic == PJ_STUN_MAGIC) {
+	status = 
+	    pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
+					 PJ_STUN_ATTR_XOR_MAPPED_ADDR,
+					 PJ_TRUE,
+					 src_addr, src_addr_len);
+    }
+
+    /* Send */
+    status = pj_stun_session_send_msg(session, PJ_TRUE, 
+				      src_addr, src_addr_len, tdata);
+    return status;
 }
 
@@ -1059,8 +1133,14 @@
     }
 
-    PJ_LOG(4,(THIS_FILE, "TURN client %s: active destination set to %s:%d",
-			 client->obj_name,
-		         pj_inet_ntoa(client->active_peer->addr.sin_addr),
-			 (int)pj_ntohs(client->active_peer->addr.sin_port)));
+    if (client->active_peer) {
+	PJ_LOG(4,(THIS_FILE, 
+		  "TURN client %s: active destination set to %s:%d",
+		  client->obj_name,
+		  pj_inet_ntoa(client->active_peer->addr.sin_addr),
+		  (int)pj_ntohs(client->active_peer->addr.sin_port)));
+    } else {
+	PJ_LOG(4,(THIS_FILE, "TURN client %s: active destination cleared",
+		  client->obj_name));
+    }
 
     /* Respond with successful response */
@@ -1163,15 +1243,25 @@
     case PJ_STUN_SEND_INDICATION:
 	status = client_handle_send_ind(client, msg);
+	break;
 
     case PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST:
 	status = client_handle_sad(client, msg,
 				   src_addr, src_addr_len);
+	break;
+
     case PJ_STUN_ALLOCATE_REQUEST:
 	status = client_handle_allocate_req(client, msg,
 					    src_addr, src_addr_len);
+	break;
+
+    case PJ_STUN_BINDING_REQUEST:
+	status = handle_binding_req(client->session, msg,
+				    src_addr, src_addr_len);
+	break;
 
     default:
 	status = client_handle_unknown_msg(client, msg,
 					   src_addr, src_addr_len);
+	break;
     }
 
@@ -1204,4 +1294,9 @@
     if (peer == NULL) {
 	/* Nope. Discard packet */
+	PJ_LOG(5,(THIS_FILE, 
+		 "TURN client %s: discarded data from %s:%d",
+		 client->obj_name,
+		 pj_inet_ntoa(client->pkt_src_addr.sin_addr),
+		 (int)pj_ntohs(client->pkt_src_addr.sin_port)));
 	return;
     }
@@ -1226,8 +1321,8 @@
 	    return;
 
-	pj_stun_msg_add_ip_addr_attr(data_ind->pool, data_ind->msg, 
-				     PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
-				     &client->pkt_src_addr,
-				     client->pkt_src_addr_len);
+	pj_stun_msg_add_sockaddr_attr(data_ind->pool, data_ind->msg, 
+				      PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
+				      &client->pkt_src_addr,
+				      client->pkt_src_addr_len);
 	pj_stun_msg_add_binary_attr(data_ind->pool, data_ind->msg,
 				    PJ_STUN_ATTR_DATA, 
Index: /pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c	(revision 1053)
+++ /pjproject/trunk/pjlib-util/src/pjstun-srv-test/usage.c	(revision 1054)
@@ -83,6 +83,4 @@
 	goto on_error;
 
-    pj_memcpy(&usage->cb, cb, sizeof(*cb));
-
     usage->type = type;
     status = pj_sock_socket(family, type, protocol, &usage->sock);
@@ -134,4 +132,10 @@
     pj_stun_server_register_usage(srv, usage);
 
+    /* Only after everything has been initialized we copy the callback,
+     * to prevent callback from being called when we encounter error
+     * during initialiation (decendant would not expect this).
+     */
+    pj_memcpy(&usage->cb, cb, sizeof(*cb));
+
     *p_usage = usage;
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjlib/include/pj/hash.h
===================================================================
--- /pjproject/trunk/pjlib/include/pj/hash.h	(revision 1053)
+++ /pjproject/trunk/pjlib/include/pj/hash.h	(revision 1054)
@@ -120,5 +120,6 @@
  *		    created.
  * @param ht	    the hash table.
- * @param key	    the key.
+ * @param key	    the key, which MUST point to buffer that remains valid
+ *		    for the duration of the entry.
  * @param keylen    the length of the key, or PJ_HASH_KEY_STRING to use the 
  *		    string length of the key.
Index: /pjproject/trunk/pjlib/src/pj/addr_resolv_sock.c
===================================================================
--- /pjproject/trunk/pjlib/src/pj/addr_resolv_sock.c	(revision 1053)
+++ /pjproject/trunk/pjlib/src/pj/addr_resolv_sock.c	(revision 1054)
@@ -56,5 +56,5 @@
 
 /* Resolve the IP address of local machine */
-pj_status_t pj_gethostip(pj_in_addr *addr)
+PJ_DEF(pj_status_t) pj_gethostip(pj_in_addr *addr)
 {
     const pj_str_t *hostname = pj_gethostname();
