Index: pjproject/trunk/pjnath/src/pjturn-srv/allocation.c
===================================================================
--- pjproject/trunk/pjnath/src/pjturn-srv/allocation.c	(revision 1877)
+++ pjproject/trunk/pjnath/src/pjturn-srv/allocation.c	(revision 1879)
@@ -669,5 +669,5 @@
     if (status != PJ_SUCCESS) {
 	/* Unable to allocate port */
-	PJ_LOG(4,(THIS_FILE, "bind() failed: err %d", 
+	PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d", 
 		  status));
 	pj_sock_close(relay->tp.sock);
@@ -689,4 +689,9 @@
 	pj_sockaddr_copy_addr(&relay->hkey.addr, &alloc->listener->addr);
     }
+    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
+	pj_sockaddr tmp_addr;
+	pj_gethostip(af, &tmp_addr);
+	pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
+    }
 
     /* Init ioqueue */
@@ -752,12 +757,16 @@
     }
 
-    /* Add LIFETIME. */
-    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
-			      PJ_STUN_ATTR_LIFETIME, interval);
-
-    /* Add BANDWIDTH */
-    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
-			      PJ_STUN_ATTR_BANDWIDTH,
-			      alloc->bandwidth);
+    /* Add LIFETIME if this is not ChannelBind. */
+    if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){
+	pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
+				  PJ_STUN_ATTR_LIFETIME, interval);
+
+	/* Add BANDWIDTH if lifetime is not zero */
+	if (interval != 0) {
+	    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg,
+				      PJ_STUN_ATTR_BANDWIDTH,
+				      alloc->bandwidth);
+	}
+    }
 
     status = pj_stun_session_send_msg(alloc->sess, PJ_TRUE, 
@@ -774,6 +783,6 @@
 /* Create new permission */
 static pj_turn_permission *create_permission(pj_turn_allocation *alloc,
-					    const pj_sockaddr_t *peer_addr,
-					    unsigned addr_len)
+					     const pj_sockaddr_t *peer_addr,
+					     unsigned addr_len)
 {
     pj_turn_permission *perm;
@@ -795,4 +804,8 @@
     perm->expiry.sec += PJ_TURN_PERM_TIMEOUT;
 
+    /* Register to hash table */
+    pj_hash_set(alloc->pool, alloc->peer_table, &perm->hkey.peer_addr, 
+	        pj_sockaddr_get_len(&perm->hkey.peer_addr), 0, perm);
+
     return perm;
 }
@@ -805,5 +818,5 @@
 
     pj_gettimeofday(&now);
-    if (PJ_TIME_VAL_LT(perm->expiry, now)) {
+    if (PJ_TIME_VAL_GT(perm->expiry, now)) {
 	/* Permission has not expired */
 	return perm;
@@ -811,6 +824,6 @@
 
     /* Remove from permission hash table */
-    pj_hash_set(NULL, alloc->peer_table, &perm->hkey, sizeof(perm->hkey),
-		0, NULL);
+    pj_hash_set(NULL, alloc->peer_table, &perm->hkey.peer_addr, 
+	        pj_sockaddr_get_len(&perm->hkey.peer_addr), 0, NULL);
 
     /* Remove from channel hash table, if assigned a channel number */
@@ -829,14 +842,10 @@
 			  unsigned addr_len)
 {
-    pj_turn_permission_key key;
     pj_turn_permission *perm;
 
-    pj_bzero(&key, sizeof(key));
-    pj_memcpy(&key, peer_addr, addr_len);
-
     /* Lookup in peer hash table */
-    perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, &key,
-					    sizeof(key), NULL);
-    return check_permission_expiry(perm);
+    perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, peer_addr,
+					     addr_len, NULL);
+    return perm ? check_permission_expiry(perm) : NULL;
 }
 
@@ -850,7 +859,7 @@
 
     /* Lookup in peer hash table */
-    perm = (pj_turn_permission*) pj_hash_get(alloc->peer_table, &chnum16,
+    perm = (pj_turn_permission*) pj_hash_get(alloc->ch_table, &chnum16,
 					    sizeof(chnum16), NULL);
-    return check_permission_expiry(perm);
+    return perm ? check_permission_expiry(perm) : NULL;
 }
 
@@ -931,6 +940,6 @@
 	    /* Discard */
 	    PJ_LOG(4,(alloc->obj_name, 
-		      "ChannelData from %s discarded: not found",
-		      alloc->info));
+		      "ChannelData from %s discarded: ch#0x%x not found",
+		      alloc->info, pj_ntohs(cd->ch_number)));
 	    goto on_return;
 	}
@@ -992,5 +1001,5 @@
 
 	/* Copy data */
-	pj_memcpy(rel->tp.rx_pkt+sizeof(pj_turn_channel_data), pkt, len);
+	pj_memcpy(rel->tp.tx_pkt+sizeof(pj_turn_channel_data), pkt, len);
 
 	/* Send to client */
@@ -1010,4 +1019,16 @@
 	    return;
 	}
+
+	pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg, 
+				      PJ_STUN_ATTR_PEER_ADDR, PJ_TRUE,
+				      src_addr, pj_sockaddr_get_len(src_addr));
+	pj_stun_msg_add_binary_attr(tdata->pool, tdata->msg,
+				    PJ_STUN_ATTR_DATA, 
+				    (const pj_uint8_t*)pkt, len);
+
+	pj_stun_session_send_msg(alloc->sess, PJ_FALSE, 
+				 &alloc->hkey.clt_addr, 
+				 pj_sockaddr_get_len(&alloc->hkey.clt_addr), 
+				 tdata);
     }
 }
@@ -1187,4 +1208,7 @@
 	    refresh_permission(p1);
 
+	    /* Send response */
+	    send_reply_ok(alloc, rdata);
+
 	    /* Done */
 	    return PJ_SUCCESS;
@@ -1212,4 +1236,9 @@
 	/* Assign channel number to permission */
 	p2->channel = PJ_STUN_GET_CH_NB(ch_attr->value);
+
+	/* Register to hash table */
+	pj_assert(sizeof(p2->channel==2));
+	pj_hash_set(alloc->pool, alloc->ch_table, &p2->channel, 
+		    sizeof(p2->channel), 0, p2);
 
 	/* Update */
