Index: pjproject/trunk/pjnath/src/pjturn-srv/server.c
===================================================================
--- pjproject/trunk/pjnath/src/pjturn-srv/server.c	(revision 1879)
+++ pjproject/trunk/pjnath/src/pjturn-srv/server.c	(revision 1913)
@@ -29,9 +29,10 @@
 #define MAX_LISTENERS		16
 #define MAX_THREADS		2
-#define MAX_NET_EVENTS		10
+#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,
@@ -42,4 +43,5 @@
 				      unsigned pkt_len,
 				      const pj_stun_rx_data *rdata,
+				      void *user_data,
 				      const pj_sockaddr_t *src_addr,
 				      unsigned src_addr_len);
@@ -78,4 +80,5 @@
 {
     pj_pool_t *pool;
+    pj_stun_session_cb sess_cb;
     pj_turn_srv *srv;
     unsigned i;
@@ -125,9 +128,4 @@
 					sizeof(srv->core.listener[0]));
 
-    /* Array of STUN sessions, one for each listener */
-    srv->core.stun_sess = (pj_stun_session**)
-			  pj_pool_calloc(pool, MAX_LISTENERS,
-					 (sizeof(srv->core.stun_sess[0])));
-
     /* Create hash tables */
     srv->tables.alloc = pj_hash_create(pool, MAX_CLIENTS);
@@ -150,4 +148,20 @@
     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, &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 */
@@ -241,5 +255,5 @@
 
     while (!srv->core.quit) {
-	pj_time_val timeout_max = {0, 500};
+	pj_time_val timeout_max = {0, 100};
 	srv_handle_events(srv, &timeout_max);
     }
@@ -278,5 +292,5 @@
     }
     
-    /* Destroy all listeners and STUN sessions associated with them. */
+    /* Destroy all listeners. */
     for (i=0; i<srv->core.lis_cnt; ++i) {
 	if (srv->core.listener[i]) {
@@ -284,8 +298,10 @@
 	    srv->core.listener[i] = NULL;
 	}
-	if (srv->core.stun_sess[i]) {
-	    pj_stun_session_destroy(srv->core.stun_sess[i]);
-	    srv->core.stun_sess[i] = NULL;
-	}
+    }
+
+    /* Destroy STUN session */
+    if (srv->core.stun_sess) {
+	pj_stun_session_destroy(srv->core.stun_sess);
+	srv->core.stun_sess = NULL;
     }
 
@@ -342,8 +358,5 @@
 					     pj_turn_listener *lis)
 {
-    pj_stun_session_cb sess_cb;
     unsigned index;
-    pj_stun_session *sess;
-    pj_status_t status;
 
     PJ_ASSERT_RETURN(srv && lis, PJ_EINVAL);
@@ -354,22 +367,4 @@
     srv->core.listener[index] = lis;
     lis->server = srv;
-
-    /* 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, lis->obj_name, 
-				    &sess_cb, PJ_FALSE, &sess);
-    if (status != PJ_SUCCESS) {
-	srv->core.listener[index] = NULL;
-	return status;
-    }
-
-    pj_stun_session_set_user_data(sess, lis);
-    pj_stun_session_set_credential(sess, PJ_STUN_AUTH_LONG_TERM, 
-				   &srv->core.cred);
-
-    srv->core.stun_sess[index] = sess;
     lis->id = index;
     srv->core.lis_cnt++;
@@ -379,19 +374,4 @@
 
     return PJ_SUCCESS;
-}
-
-
-/*
- * Send packet with this listener.
- */
-PJ_DEF(pj_status_t) pj_turn_listener_sendto(pj_turn_listener *listener,
-					    const void *packet,
-					    pj_size_t size,
-					    unsigned flag,
-					    const pj_sockaddr_t *addr,
-					    int addr_len)
-{
-    pj_assert(listener->id != PJ_TURN_INVALID_LIS_ID);
-    return listener->sendto(listener, packet, size, flag, addr, addr_len);
 }
 
@@ -412,8 +392,4 @@
 	    srv->core.lis_cnt--;
 	    listener->id = PJ_TURN_INVALID_LIS_ID;
-	    if (srv->core.stun_sess[i]) {
-		pj_stun_session_destroy(srv->core.stun_sess[i]);
-		srv->core.stun_sess[i] = NULL;
-	    }
 	    break;
 	}
@@ -423,4 +399,24 @@
     /* 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);
 }
 
@@ -467,17 +463,18 @@
  */
 static pj_status_t on_tx_stun_msg( pj_stun_session *sess,
-				   const void *pkt,
-				   pj_size_t pkt_size,
+				   void *token,
+				   const void *pdu,
+				   pj_size_t pdu_size,
 				   const pj_sockaddr_t *dst_addr,
 				   unsigned addr_len)
 {
-    pj_turn_listener *listener;
+    pj_turn_transport *transport = (pj_turn_transport*) token;
     
-    listener = (pj_turn_listener*) pj_stun_session_get_user_data(sess);
-
-    PJ_ASSERT_RETURN(listener!=NULL, PJ_EINVALIDOP);
-
-    return pj_turn_listener_sendto(listener, pkt, pkt_size, 0, 
-				   dst_addr, addr_len);
+    PJ_ASSERT_RETURN(transport!=NULL, PJ_EINVALIDOP);
+
+    PJ_UNUSED_ARG(sess);
+
+    return transport->sendto(transport, pdu, pdu_size, 0, 
+			     dst_addr, addr_len);
 }
 
@@ -485,4 +482,5 @@
 /* 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, 
@@ -504,5 +502,6 @@
 
     /* Send the response */
-    return pj_stun_session_send_msg(sess, cache, dst_addr,  addr_len, tdata);
+    return pj_stun_session_send_msg(sess, transport, cache, PJ_FALSE, 
+				    dst_addr,  addr_len, tdata);
 }
 
@@ -510,14 +509,15 @@
 /* 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.
+ * pj_turn_srv_on_rx_pkt() function below.
  */
 static pj_status_t on_rx_stun_request(pj_stun_session *sess,
-				      const pj_uint8_t *pkt,
-				      unsigned pkt_len,
+				      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_listener *listener;
+    pj_turn_transport *transport;
     const pj_stun_msg *msg = rdata->msg;
     pj_turn_srv *srv;
@@ -525,13 +525,13 @@
     pj_status_t status;
 
-    PJ_UNUSED_ARG(pkt);
-    PJ_UNUSED_ARG(pkt_len);
-
-    listener = (pj_turn_listener*) pj_stun_session_get_user_data(sess);
-    srv = listener->server;
+    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, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
+	stun_respond(sess, transport, rdata, PJ_STUN_SC_ALLOCATION_MISMATCH,
 		     NULL, PJ_FALSE, src_addr, src_addr_len);
 	return PJ_SUCCESS;
@@ -541,5 +541,5 @@
      * in this function.
      */
-    status = pj_turn_allocation_create(listener, src_addr, src_addr_len,
+    status = pj_turn_allocation_create(transport, src_addr, src_addr_len,
 				       rdata, sess, &alloc);
     if (status != PJ_SUCCESS) {
@@ -577,26 +577,41 @@
     } else {
 	/* Otherwise this is a new client */
-	unsigned options, lis_id;
+	unsigned options;
+	unsigned parsed_len;
 	pj_status_t status;
 
 	/* Check that this is a STUN message */
 	options = PJ_STUN_CHECK_PACKET;
-	if (pkt->listener->tp_type == PJ_TURN_TP_UDP)
+	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) {
-	    char errmsg[PJ_ERR_MSG_SIZE];
-	    char ip[PJ_INET6_ADDRSTRLEN+10];
-
-	    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));
+	    /* 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;
 	}
-
-	lis_id = pkt->listener->id;
 
 	/* Hand over processing to STUN session. This will trigger
@@ -605,7 +620,8 @@
 	 */
 	options &= ~PJ_STUN_CHECK_PACKET;
-	status = pj_stun_session_on_rx_pkt(srv->core.stun_sess[lis_id], 
-					   pkt->pkt, pkt->len, options, NULL,
-					   &pkt->src.clt_addr, 
+	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) {
@@ -618,8 +634,19 @@
 		      pj_sockaddr_print(&pkt->src.clt_addr, ip, sizeof(ip), 3),
 		      errmsg));
-	    return;
-	}
-    }
-}
-
-
+	}
+
+	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;
+	    }
+	}
+    }
+}
+
+
