doubango/tinyNET/src/turn/tnet_turn.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 ///*
 //* Copyright (C) 2010-2011 Mamadou Diop.
 //*
 //* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
 //*	
 //* This file is part of Open Source Doubango Framework.
 //*
 //* DOUBANGO 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 3 of the License, or
 //* (at your option) any later version.
 //*	
 //* DOUBANGO 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 DOUBANGO.
 //*
 //*/
 //
 ///**@file tnet_turn.c
 // * @brief Traversal Using Relays around NAT (TURN) implementation as per 'draft-ietf-behave-turn-16', 'draft-ietf-behave-turn-tcp-05'
 // *		 and 'draft-ietf-behave-turn-ipv6'.
 // *			http://tools.ietf.org/html/draft-ietf-behave-turn-16
 // *			http://tools.ietf.org/html/draft-ietf-behave-turn-tcp-05
 // *			http://tools.ietf.org/html/draft-ietf-behave-turn-ipv6-07
 // *
 // * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
 // *
 //
 // */
 //#include "tnet_turn.h"
 //
 //#include "tnet_turn_message.h"
 //
 //#include "tsk_string.h"
 //#include "tsk_memory.h"
 //
 //#include "../tnet_nat.h"
 //#include "../tnet_utils.h"
 //#include "../tnet_endianness.h"
 //
 //#include "tsk_md5.h"
 //#include "tsk_debug.h"
 //
 //#include <string.h>
 //
 ///**@defgroup tnet_turn_group TURN(draft-ietf-behave-turn-16) implementation.
 //*/
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_turn_channel_binding_t* tnet_turn_channel_binding_create(const tnet_turn_allocation_t *allocation)
 //{
 //	return tsk_object_new(tnet_turn_channel_binding_def_t, allocation);
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_turn_permission_t* tnet_turn_permission_create(uint32_t timeout)
 //{
 //	return tsk_object_new(tnet_turn_permission_def_t, timeout);
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_turn_allocation_t* tnet_turn_allocation_create(tnet_fd_t fd, tnet_socket_type_t socket_type, const char* server_address, tnet_port_t server_port, const char* username, const char* password)
 //{
 //	return tsk_object_new(tnet_turn_allocation_def_t, fd, socket_type, server_address, server_port, username, password);
 //}
 //
 ///*
 //- IMPORTANT: 16.  Detailed Example
 //- It is suggested that the client refresh the allocation roughly 1 minute before it expires.
 //- If the client wishes to immediately delete an existing allocation, it includes a LIFETIME attribute with a value of 0.
 //*/
 //
 //typedef tnet_stun_pkt_req_t* (*tnet_turn_create_request_func)(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app);
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_stun_pkt_type_t type)
 //{
 //	tnet_stun_attr_t* attribute;
 //	tnet_stun_pkt_req_t *request = tnet_stun_message_create(context->username, context->password);
 //
 //	if(request){
 //		request->type = type;
 //
 //		request->fingerprint = context->enable_fingerprint;
 //		request->integrity = context->enable_integrity;
 //		request->nointegrity = !request->integrity;
 //		request->dontfrag = context->enable_dontfrag;
 //		request->realm = tsk_strdup(allocation->realm);
 //		request->nonce = tsk_strdup(allocation->nonce);
 //
 //		/* Create random transaction id */
 //		{	
 //			tsk_istr_t random;
 //			tsk_md5digest_t digest;
 //
 //			tsk_strrandom(&random);
 //			TSK_MD5_DIGEST_CALC(random, sizeof(random), digest);
 //
 //			memcpy(request->transac_id, digest, TNET_STUN_TRANSACID_SIZE);
 //		}
 //
 //		/* Add software attribute */
 //		if(allocation->software){
 //			attribute = (tnet_stun_attr_t*)tnet_stun_attribute_software_create(allocation->software, tsk_strlen(allocation->software));
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //	}
 //
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_allocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t* request =  tnet_turn_create_request(context, allocation, stun_allocate_request);
 //	if(request){
 //		tnet_stun_attr_t* attribute;
 //
 //		/* Add Requested transport. */
 //		if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_reqtrans_create(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type) ? TNET_PROTO_UDP: TNET_PROTO_TCP))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //
 //		/* Add lifetime */
 //		if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_lifetime_create(tnet_ntohl(allocation->timeout)))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //
 //		/* Add Event Port */
 //		if(context->enable_evenport && (attribute = (tnet_stun_attr_t*)tnet_turn_attribute_even_port_create(context->enable_evenport))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //	}
 //
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t *request = tnet_turn_create_request_allocate(context, allocation, app);
 //	if(request){
 //		request->type = stun_refresh_request;
 //	}
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_unallocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t *request = tnet_turn_create_request_refresh(context, allocation, app);
 //	if(request){
 //		((tnet_turn_attribute_lifetime_t*)tnet_stun_message_get_attribute(request, stun_lifetime))->value = 0;
 //	}
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_channel_bind(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t* request =  tnet_turn_create_request(context, allocation, stun_channelbind_request);
 //	if(request){
 //		const tnet_turn_channel_binding_t* channel_binding;
 //		tnet_turn_attribute_t *attribute;
 //		tnet_turn_channel_binding_id_t number;
 //		uint32_t lifetime;
 //		
 //		
 //		channel_binding = va_arg(*app, const tnet_turn_channel_binding_t *);
 //		number = tnet_htons(channel_binding->id);
 //		lifetime = tnet_htonl(channel_binding->timeout);
 //		attribute = tsk_object_ref(channel_binding->xpeer);
 //
 //		/* XOR-PEER */
 //		tnet_stun_message_add_attribute(request, &attribute);
 //
 //		/* CHANNEL-NUMBER */
 //		if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_channelnum_create(number))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //
 //		/* LIFETIME */
 //		if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_lifetime_create(lifetime))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //	}
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_channel_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	return tnet_turn_create_request_channel_bind(context, allocation, app);
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_sendindication(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t* request =  tnet_turn_create_request(context, allocation, stun_send_indication);
 //	if(request){
 //		tnet_turn_attribute_t *attribute;
 //		tnet_turn_attribute_xpeer_addr_t* xpeer  = tsk_object_ref(va_arg(*app, tnet_turn_attribute_xpeer_addr_t *));
 //		const void* data = va_arg(*app, const void *);
 //		tsk_size_t size = va_arg(*app, tsk_size_t);
 //		
 //		/*
 //			draft-ietf-behave-turn-16 - 10.1.  Forming a Send Indication
 //
 //			When forming a Send indication, the client MUST include a XOR-PEER-
 //			ADDRESS attribute and a DATA attribute.  The XOR-PEER-ADDRESS
 //			attribute contains the transport address of the peer to which the
 //			data is to be sent, and the DATA attribute contains the actual
 //			application data to be sent to the peer.
 //		*/
 //
 //		/* XOR-PEER-ADDRESS */
 //		tnet_stun_message_add_attribute(request, (tnet_turn_attribute_t**)&xpeer);
 //
 //		/* DATA */
 //		if((attribute = (tnet_stun_attr_t*)tnet_turn_attribute_data_create(data, size))){
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}
 //	}
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_stun_pkt_req_t* tnet_turn_create_request_permission(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
 //{
 //	tnet_stun_pkt_req_t* request =  tnet_turn_create_request(context, allocation, stun_createpermission_request);
 //	if(request){
 //		//--const char* ipaddress = va_arg(*app, const char *);
 //
 //		/* XOR-PEER-ADDRESS */
 //		tnet_turn_attribute_xpeer_addr_t* attribute = tnet_turn_attribute_xpeer_addr_create_null();
 //		attribute->family = stun_ipv4;
 //		TNET_STUN_ATTRIBUTE(attribute)->length = 8;
 //
 //		attribute->xaddress[0] = 0x79;
 //		attribute->xaddress[1] = 0xA1;
 //		attribute->xaddress[2] = 0x83;
 //		attribute->xaddress[3] = 0x47;
 //		
 //		tnet_stun_message_add_attribute(request, (tnet_stun_attr_t**)&attribute);
 //
 //		/*if((attribute = tnet_turn_attribute_even_port_create(context->enable_evenport)))
 //		{
 //			tnet_stun_message_add_attribute(request, &attribute);
 //		}*/
 //	}
 //	return request;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_send_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_turn_create_request_func funcptr, ...)
 //{
 //	tnet_stun_pkt_req_t *request;
 //	int ret = -1;
 //	va_list ap;
 //
 //	va_start(ap, funcptr);
 //	request =  funcptr(context, allocation, &ap);
 //	va_end(ap);
 //
 //	if(request){
 //		if(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type)){
 //			tnet_stun_pkt_resp_t *response = tnet_stun_send_unreliably(allocation->localFD, 500, 7, request, (struct sockaddr*)&allocation->server);
 //			if(response)
 //			{
 //				if(TNET_STUN_PKT_RESP_IS_ERROR(response)){
 //					short code = tnet_stun_message_get_errorcode(response);
 //					const char* realm = tnet_stun_message_get_realm(response);
 //					const char* nonce = tnet_stun_message_get_nonce(response);
 //
 //					if(code == 401 && realm && nonce){
 //						if(!allocation->nonce)
 //						{	/* First time we get a nonce */
 //							tsk_strupdate(&allocation->nonce, nonce);
 //							tsk_strupdate(&allocation->realm, realm);
 //							
 //							/* Delete the message and response before retrying*/
 //							TSK_OBJECT_SAFE_FREE(response);
 //							TSK_OBJECT_SAFE_FREE(request);
 //
 //							// Send again using new transaction identifier
 //							return tnet_turn_send_request(context, allocation, funcptr);
 //						}
 //						else{
 //							ret = -3;
 //						}
 //					}
 //					else
 //					{
 //						TSK_DEBUG_ERROR("Server error code: %d", code);
 //						ret = -2;
 //					}
 //				}
 //				else /* Any (allocate, permission, channel binding ...) success response */
 //				{
 //					if(response->type == stun_allocate_success_response) /* Allocate success response */
 //					{
 //						/* LifeTime */
 //						{
 //							int32_t lifetime = tnet_stun_message_get_lifetime(response);
 //							if(lifetime>=0)
 //							{
 //								allocation->timeout = lifetime;
 //							}
 //						}
 //						/* STUN mapped or xmapped address */
 //						{
 //							const tnet_stun_attr_t *attribute;
 //							if((attribute = tnet_stun_message_get_attribute(response, stun_xor_mapped_address)))
 //							{
 //								allocation->xmaddr = tsk_object_ref((void*)attribute);
 //							}
 //							else if((attribute= tnet_stun_message_get_attribute(response, stun_mapped_address)))
 //							{
 //								allocation->maddr = tsk_object_ref((void*)attribute);
 //							}
 //						}
 //					}
 //
 //					/* Set ret to zero (success) */
 //					ret = 0;
 //				}
 //			}
 //			else{
 //				ret = -4;
 //			}
 //			TSK_OBJECT_SAFE_FREE(response);
 //		}
 //	}
 //	
 //	TSK_OBJECT_SAFE_FREE(request);
 //	return ret;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_turn_allocation_id_t tnet_turn_allocate(const tnet_nat_context_t* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)
 //{
 //	tnet_turn_allocation_id_t id = TNET_TURN_INVALID_ALLOCATION_ID;
 //	
 //	if(nat_context){
 //		int ret;
 //		tnet_turn_allocation_t* allocation = tnet_turn_allocation_create(localFD, nat_context->socket_type, nat_context->server_address, nat_context->server_port, nat_context->username, nat_context->password);
 //		allocation->software = tsk_strdup(nat_context->software);
 //		
 //		if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_allocate))){
 //			TSK_DEBUG_ERROR("TURN allocation failed with error code:%d.", ret);
 //			TSK_OBJECT_SAFE_FREE(allocation);
 //		}
 //		else{
 //			id = allocation->id;
 //			tsk_list_push_back_data(nat_context->allocations, (void**)&allocation);
 //		}
 //	}
 //
 //	return id;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_allocation_refresh(const struct struct tnet_nat_ctx_s* nat_context, tnet_turn_allocation_t *allocation)
 //{
 //	if(nat_context && allocation){
 //		int ret;
 //
 //		if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_refresh))){
 //			TSK_DEBUG_ERROR("TURN allocation refresh failed with error code:%d.", ret);
 //			return -1;
 //		}
 //		else{
 //			return 0;
 //		}
 //	}
 //	return -1;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_unallocate(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation)
 //{
 //	if(nat_context && allocation){
 //		int ret;
 //
 //		if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_unallocate))){
 //			TSK_DEBUG_ERROR("TURN unallocation failed with error code:%d.", ret);
 //			return -1;
 //		}
 //		else{
 //			tsk_list_remove_item_by_data(nat_context->allocations, allocation);
 //			return 0;
 //		}
 //	}
 //	return -1;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)
 //{
 //	tnet_turn_channel_binding_id_t id = TNET_TURN_INVALID_CHANNEL_BINDING_ID;
 //	tnet_turn_channel_binding_t *channel_binding = 0;
 //
 //	if(nat_context && allocation){
 //		int ret;
 //		
 //		channel_binding = tnet_turn_channel_binding_create(allocation);
 //		
 //		if(channel_binding){
 //			if(((struct sockaddr*)peer)->sa_family == AF_INET){
 //				struct sockaddr_in *sin = ((struct sockaddr_in*)peer);
 //				uint32_t _sin_addr;
 //
 //				channel_binding->xpeer = tnet_turn_attribute_xpeer_addr_create_null();
 //				channel_binding->xpeer->family = stun_ipv4;
 //				channel_binding->xpeer->xport = ((sin->sin_port) ^ tnet_htons(0x2112));
 //				
 //				_sin_addr = tnet_htonl_2(&sin->sin_addr) ^tnet_htonl(kStunMagicCookieLong);
 //				memcpy(channel_binding->xpeer->xaddress, &_sin_addr, sizeof(_sin_addr));
 //			}
 //			else if(((struct sockaddr*)peer)->sa_family == AF_INET6){
 //				TSK_DEBUG_ERROR("IPv6 not supported.");
 //				goto  bail;
 //			}
 //			else{
 //				TSK_DEBUG_ERROR("Invalid address family.");
 //				goto  bail;
 //			}
 //		}
 //		else{
 //			goto bail;
 //		}
 //
 //		if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_channel_bind, channel_binding))){
 //			TSK_DEBUG_ERROR("TURN (CHANNEL-BIND) failed with error code:%d.", ret);
 //			TSK_OBJECT_SAFE_FREE(channel_binding);
 //			
 //			goto bail;
 //		}
 //		else{
 //			id = channel_binding->id;
 //			tsk_list_push_back_data(allocation->channel_bindings, (void**)&channel_binding);
 //		}
 //	}
 //
 //bail:
 //	TSK_OBJECT_SAFE_FREE(channel_binding);
 //	return id;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_channel_refresh(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind)
 //{
 //	if(nat_context && channel_bind){
 //		int ret;
 //
 //		if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_channel_refresh, channel_bind))){
 //			TSK_DEBUG_ERROR("TURN channel-binding refresh failed with error code:%d.", ret);
 //			return -1;
 //		}
 //		else return 0;
 //	}
 //	return -1;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_channel_senddata(const struct struct tnet_nat_ctx_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication)
 //{
 //	tnet_turn_channel_data_t *channel_data = 0;
 //	tsk_buffer_t *output = 0;
 //
 //	int ret = -1;
 //
 //	if(nat_context && channel_bind)
 //	{
 //		if(indication)
 //		{	/* SEND INDICATION */
 //			if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_sendindication, channel_bind->xpeer, data, size)))
 //			{
 //				TSK_DEBUG_ERROR("TURN channel send indication failed with error code:%d.", ret);
 //				return -1;
 //			}
 //			else return 0;
 //		}
 //		else
 //		{	/* CHANNEL DATA */
 //			if(!(channel_data = tnet_turn_channel_data_create(channel_bind->id, size, data)))
 //			{
 //				TSK_DEBUG_ERROR("Failed to create TURN CHANNEL-DATA message.");
 //				goto bail;
 //			}
 //
 //			if(!(output = tnet_turn_channel_data_serialize(channel_data)))
 //			{
 //				TSK_DEBUG_ERROR("Failed to serialize TURN CHANNEL-DATA.");
 //				goto bail;
 //			}
 //
 //			if(tnet_sockfd_sendto(channel_bind->allocation->localFD, (struct sockaddr*)&channel_bind->allocation->server, output->data, output->size) <= 0)
 //			{
 //				TNET_PRINT_LAST_ERROR("Failed to send TURN messsage.");
 //				ret = -2;
 //				goto bail;
 //			}
 //			else
 //			{
 //				ret = 0;
 //			}
 //		}
 //	}
 //bail:
 //	TSK_OBJECT_SAFE_FREE(channel_data);
 //	TSK_OBJECT_SAFE_FREE(output);
 //
 //	return ret;
 //}
 //
 ///**@ingroup tnet_turn_group
 //*/
 //int tnet_turn_add_permission(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout)
 //{
 //	if(nat_context && allocation)
 //	{
 //		int ret;
 //
 //		if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_permission, ipaddress)))
 //		{
 //			TSK_DEBUG_ERROR("TURN (ADD) permission failed with error code:%d.", ret);
 //			return -1;
 //		}
 //		else
 //		{
 //			//tnet_turn_permission_t *permission = tnet_turn_permission_create(timeout);
 //			//tsk_list_remove_item_by_data(context->allocations, allocation);
 //			return 0;
 //		}
 //	}
 //	return -1;
 //}
 //
 ////=================================================================================================
 ////	TURN CHANNEL-BINDING object definition
 ////
 //static tsk_object_t* tnet_turn_channel_binding_ctor(tsk_object_t * self, va_list * app)
 //{
 //	tnet_turn_channel_binding_t *channel_binding = self;
 //	if(channel_binding){
 //		static tnet_turn_channel_binding_id_t __allocation_unique_id = 0x4000; /* 0x4000 through 0x7FFF */		
 //		
 //		channel_binding->id = __allocation_unique_id++;
 //		channel_binding->allocation = va_arg(*app, const tnet_turn_allocation_t *);
 //		channel_binding->timeout = TNET_TURN_CHANBIND_TIMEOUT_DEFAULT; /* 10 minutes as per draft-ietf-behave-turn-16 subclause 11 */
 //
 //		if(__allocation_unique_id >= 0x7FFF){
 //			__allocation_unique_id = 0x4000;
 //		}
 //	}
 //	return self;
 //}
 //
 //static tsk_object_t* tnet_turn_channel_binding_dtor(tsk_object_t * self)
 //{ 
 //	tnet_turn_channel_binding_t *channel_binding = self;
 //	if(channel_binding){
 //		TSK_OBJECT_SAFE_FREE(channel_binding->xpeer);
 //	}
 //	
 //	return self;
 //}
 //
 //static const tsk_object_def_t tnet_turn_channel_binding_def_s = 
 //{
 //	sizeof(tnet_turn_channel_binding_t),
 //	tnet_turn_channel_binding_ctor, 
 //	tnet_turn_channel_binding_dtor,
 //	tsk_null, 
 //};
 //const tsk_object_def_t *tnet_turn_channel_binding_def_t = &tnet_turn_channel_binding_def_s;
 //
 ////=================================================================================================
 ////	TURN PERMISSION object definition
 ////
 //static tsk_object_t* tnet_turn_permission_ctor(tsk_object_t * self, va_list * app)
 //{
 //	tnet_turn_permission_t *permission = self;
 //	if(permission){
 //		permission->timeout = va_arg(*app, uint32_t);
 //	}
 //	return self;
 //}
 //
 //static tsk_object_t* tnet_turn_permission_dtor(tsk_object_t * self)
 //{ 
 //	tnet_turn_permission_t *permission = self;
 //	if(permission){
 //		TSK_OBJECT_SAFE_FREE(permission->xpeer);
 //	}
 //	
 //	return self;
 //}
 //
 //static const tsk_object_def_t tnet_turn_permission_def_s = 
 //{
 //	sizeof(tnet_turn_permission_t),
 //	tnet_turn_permission_ctor, 
 //	tnet_turn_permission_dtor,
 //	tsk_null, 
 //};
 //const tsk_object_def_t *tnet_turn_permission_def_t = &tnet_turn_permission_def_s;
 //
 //
 //
 ////=================================================================================================
 ////	TURN ALLOCATION object definition
 ////
 //static tsk_object_t* tnet_turn_allocation_ctor(tsk_object_t * self, va_list * app)
 //{
 //	tnet_turn_allocation_t *allocation = self;
 //	if(allocation){
 //		static tnet_turn_allocation_id_t __allocation_unique_id = 0;
 //		
 //		const char* server_address;
 //		tnet_port_t server_port;
 //
 //		allocation->id = ++__allocation_unique_id;
 //
 //		allocation->localFD = va_arg(*app, tnet_fd_t);
 //		allocation->socket_type = va_arg(*app, tnet_socket_type_t);
 //	
 //		server_address = va_arg(*app, const char*);
 //		server_port = (tnet_port_t)va_arg(*app, unsigned);
 //#else
 //		server_port = va_arg(*app, tnet_port_t);
 //
 //		allocation->username = tsk_strdup(va_arg(*app, const char*));
 //		allocation->password = tsk_strdup(va_arg(*app, const char*));
 //
 //		tnet_sockaddr_init(server_address, server_port, allocation->socket_type, &allocation->server);
 //		allocation->timeout = 600;
 //
 //		allocation->channel_bindings = tsk_list_create();
 //		allocation->permissions = tsk_list_create();
 //	}
 //	return self;
 //}
 //
 //static tsk_object_t* tnet_turn_allocation_dtor(tsk_object_t * self)
 //{ 
 //	tnet_turn_allocation_t *allocation = self;
 //	if(allocation){
 //		TSK_FREE(allocation->relay_address);
 //
 //		TSK_FREE(allocation->username);
 //		TSK_FREE(allocation->password);
 //		TSK_FREE(allocation->realm);
 //		TSK_FREE(allocation->nonce);
 //
 //		TSK_FREE(allocation->software);
 //		
 //		TSK_OBJECT_SAFE_FREE(allocation->xmaddr);
 //		TSK_OBJECT_SAFE_FREE(allocation->maddr);
 //
 //		TSK_OBJECT_SAFE_FREE(allocation->channel_bindings);
 //		TSK_OBJECT_SAFE_FREE(allocation->permissions);
 //	}
 //	
 //	return self;
 //}
 //
 //static const tsk_object_def_t tnet_turn_allocation_def_s = 
 //{
 //	sizeof(tnet_turn_allocation_t),
 //	tnet_turn_allocation_ctor, 
 //	tnet_turn_allocation_dtor,
 //	tsk_null, 
 //};
 //const tsk_object_def_t *tnet_turn_allocation_def_t = &tnet_turn_allocation_def_s;
 //