720 lines
21 KiB
C
720 lines
21 KiB
C
/*
|
|
* Copyright (C) 2009 Mamadou Diop.
|
|
*
|
|
* Contact: Mamadou Diop <diopmamadou@yahoo.fr>
|
|
*
|
|
* 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)yahoo.fr>
|
|
*
|
|
* @date Created: Sat Nov 8 16:54:58 2009 mdiop
|
|
*/
|
|
#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 "tsk_md5.h"
|
|
#include "tsk_debug.h"
|
|
|
|
#include <string.h>
|
|
|
|
/**@defgroup tnet_turn_group TURN(draft-ietf-behave-turn-16) implementation.
|
|
*/
|
|
|
|
/*
|
|
- 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_request_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_request_t* tnet_turn_create_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_stun_message_type_t type)
|
|
{
|
|
tnet_stun_attribute_t* attribute;
|
|
tnet_stun_request_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->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->transaction_id, digest, TNET_STUN_TRANSACID_SIZE);
|
|
}
|
|
|
|
/* Add software attribute */
|
|
if(allocation->software)
|
|
{
|
|
attribute = TNET_STUN_ATTRIBUTE_SOFTWARE_CREATE(allocation->software, strlen(allocation->software));
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
}
|
|
|
|
return request;
|
|
}
|
|
|
|
/**@ingroup tnet_turn_group
|
|
*/
|
|
tnet_stun_request_t* tnet_turn_create_request_allocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_t* request = tnet_turn_create_request(context, allocation, stun_allocate_request);
|
|
if(request)
|
|
{
|
|
tnet_stun_attribute_t* attribute;
|
|
|
|
/* Add Requested transport. */
|
|
if((attribute = 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_TURN_ATTRIBUTE_LIFETIME_CREATE(ntohl(allocation->timeout))))
|
|
{
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
|
|
/* Add Event Port */
|
|
if((attribute = TNET_TURN_ATTRIBUTE_EVEN_PORT_CREATE(context->enable_evenport)))
|
|
{
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
}
|
|
|
|
return request;
|
|
}
|
|
|
|
/**@ingroup tnet_turn_group
|
|
*/
|
|
tnet_stun_request_t* tnet_turn_create_request_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_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_request_t* tnet_turn_create_request_unallocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_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_request_t* tnet_turn_create_request_channel_bind(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_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 = htons(channel_binding->id);
|
|
lifetime = 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_TURN_ATTRIBUTE_CHANNELNUM_CREATE(number)))
|
|
{
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
|
|
/* LIFETIME */
|
|
if((attribute = TNET_TURN_ATTRIBUTE_LIFETIME_CREATE(lifetime)))
|
|
{
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
}
|
|
return request;
|
|
}
|
|
|
|
/**@ingroup tnet_turn_group
|
|
*/
|
|
tnet_stun_request_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_request_t* tnet_turn_create_request_sendindication(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_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 *);
|
|
size_t size = va_arg(*app, 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_TURN_ATTRIBUTE_DATA_CREATE(data, size)))
|
|
{
|
|
tnet_stun_message_add_attribute(request, &attribute);
|
|
}
|
|
}
|
|
return request;
|
|
}
|
|
|
|
/**@ingroup tnet_turn_group
|
|
*/
|
|
tnet_stun_request_t* tnet_turn_create_request_permission(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
|
|
{
|
|
tnet_stun_request_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_attribute_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_request_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_response_t *response = tnet_stun_send_unreliably(allocation->localFD, 500, 7, request, (struct sockaddr*)&allocation->server);
|
|
if(response)
|
|
{
|
|
if(TNET_STUN_RESPONSE_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_attribute_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 tnet_nat_context_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);
|
|
|
|
channel_binding->xpeer = TNET_TURN_ATTRIBUTE_XPEER_ADDR_CREATE_NULL();
|
|
channel_binding->xpeer->family = stun_ipv4;
|
|
channel_binding->xpeer->xport = ((sin->sin_port) ^ htons(0x2112));
|
|
|
|
*((uint32_t*)channel_binding->xpeer->xaddress) = ((*((uint32_t*)&sin->sin_addr)) ^htonl(TNET_STUN_MAGIC_COOKIE));
|
|
}
|
|
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 tnet_nat_context_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 tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, 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 void* tnet_turn_channel_binding_create(void * 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 void* tnet_turn_channel_binding_destroy(void * 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_create,
|
|
tnet_turn_channel_binding_destroy,
|
|
0,
|
|
};
|
|
const void *tnet_turn_channel_binding_def_t = &tnet_turn_channel_binding_def_s;
|
|
|
|
//=================================================================================================
|
|
// TURN PERMISSION object definition
|
|
//
|
|
static void* tnet_turn_permission_create(void * self, va_list * app)
|
|
{
|
|
tnet_turn_permission_t *permission = self;
|
|
if(permission)
|
|
{
|
|
permission->timeout = va_arg(*app, uint32_t);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
static void* tnet_turn_permission_destroy(void * 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_create,
|
|
tnet_turn_permission_destroy,
|
|
0,
|
|
};
|
|
const void *tnet_turn_permission_def_t = &tnet_turn_permission_def_s;
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// TURN ALLOCATION object definition
|
|
//
|
|
static void* tnet_turn_allocation_create(void * 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*);
|
|
#if defined(__GNUC__)
|
|
server_port = (tnet_port_t)va_arg(*app, unsigned);
|
|
#else
|
|
server_port = va_arg(*app, tnet_port_t);
|
|
#endif
|
|
|
|
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 void* tnet_turn_allocation_destroy(void * 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_create,
|
|
tnet_turn_allocation_destroy,
|
|
0,
|
|
};
|
|
const void *tnet_turn_allocation_def_t = &tnet_turn_allocation_def_s;
|
|
|