summaryrefslogtreecommitdiffstats
path: root/tinyNET/src/turn
diff options
context:
space:
mode:
Diffstat (limited to 'tinyNET/src/turn')
-rw-r--r--tinyNET/src/turn/tnet_turn.c700
-rw-r--r--tinyNET/src/turn/tnet_turn.h175
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.c649
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.h196
-rw-r--r--tinyNET/src/turn/tnet_turn_message.c170
-rw-r--r--tinyNET/src/turn/tnet_turn_message.h75
6 files changed, 1965 insertions, 0 deletions
diff --git a/tinyNET/src/turn/tnet_turn.c b/tinyNET/src/turn/tnet_turn.c
new file mode 100644
index 0000000..08adb13
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.c
@@ -0,0 +1,700 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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.org>
+ *
+ * @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 "../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_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_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_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_stun_attribute_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_attribute_t*)tnet_turn_attribute_lifetime_create(tnet_ntohl(allocation->timeout)))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+
+ /* Add Event Port */
+ if((attribute = (tnet_stun_attribute_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_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 = 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_attribute_t*)tnet_turn_attribute_channelnum_create(number))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+
+ /* LIFETIME */
+ if((attribute = (tnet_stun_attribute_t*)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 *);
+ 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_attribute_t*)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);
+ 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(TNET_STUN_MAGIC_COOKIE);
+ 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 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, 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*);
+#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 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;
+
diff --git a/tinyNET/src/turn/tnet_turn.h b/tinyNET/src/turn/tnet_turn.h
new file mode 100644
index 0000000..0a43207
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.h
@@ -0,0 +1,175 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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.h
+ * @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.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_H
+#define TNET_TURN_H
+
+#include "tinynet_config.h"
+
+#include "turn/tnet_turn_attribute.h"
+
+#include "tnet_proto.h"
+#include "tnet_socket.h"
+#include "tnet_types.h"
+
+#include "tsk_object.h"
+
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_PERMISSION_TIMEOUT_DEFAULT
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_CHANBIND_TIMEOUT_DEFAULT
+*/
+TNET_BEGIN_DECLS
+
+#define TNET_TURN_PERMISSION_TIMEOUT_DEFAULT 300 /* draft-ietf-behave-turn-16 subclause 8 */
+#define TNET_TURN_CHANBIND_TIMEOUT_DEFAULT 600 /* draft-ietf-behave-turn-16 subclause 11 */
+
+
+/**@ingroup tnet_turn_group
+* @def tnet_turn_allocation_id_t.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_INVALID_ALLOCATION_ID.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_IS_VALID_ALLOCATION_ID.
+*/
+typedef uint64_t tnet_turn_allocation_id_t;
+#define TNET_TURN_INVALID_ALLOCATION_ID 0
+#define TNET_TURN_IS_VALID_ALLOCATION_ID(id) (id != TNET_TURN_INVALID_ALLOCATION_ID)
+
+/**@ingroup tnet_turn_group
+* @def tnet_turn_channel_binding_id_t.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_INVALID_CHANNEL_BINDING_ID.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_IS_VALID_CHANNEL_BINDING_ID.
+*/
+typedef uint16_t tnet_turn_channel_binding_id_t;
+#define TNET_TURN_INVALID_CHANNEL_BINDING_ID 0x00
+#define TNET_TURN_IS_VALID_CHANNEL_BINDING_ID(id) ( (0x4000 <= id) && (id <= 0x7FFF) ) /* see draft-ietf-behave-turn-16 subcaluse 11. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_permission_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_attribute_xpeer_addr_t *xpeer;
+ uint32_t timeout; /**< Timeout value in seconds. Default is 300s(5 minutes). */
+}
+tnet_turn_permission_t;
+typedef tsk_list_t tnet_turn_permissions_L_t; /**< List of @ref tnet_turn_permission_t elements. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_channel_binding_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_channel_binding_id_t id;
+ const struct tnet_turn_allocation_s *allocation;
+ tnet_turn_attribute_xpeer_addr_t *xpeer;
+ uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+}
+tnet_turn_channel_binding_t;
+typedef tsk_list_t tnet_turn_channel_bindings_L_t; /**< List of @ref tnet_turn_channel_binding_t elements. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_allocation_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_allocation_id_t id; /**< Unique id. */
+
+ char* relay_address; /**< the relayed transport address */
+ //! Server reflexive address of the local socket(STUN1 as per RFC 3489).
+ tnet_stun_attribute_mapped_addr_t *maddr;
+ //! XORed server reflexive address (STUN2 as per RFC 5389).
+ tnet_stun_attribute_xmapped_addr_t *xmaddr;
+
+ /* 5-tuple */
+ tnet_fd_t localFD;
+ tnet_socket_type_t socket_type;
+
+ struct sockaddr_storage server;
+
+ /*---*/
+
+ /* the authentication information */
+ char* username;
+ char* password;
+ char* realm;
+ char* nonce;
+ /*---*/
+
+ /* the time-to-expiry */
+ uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+ /*---*/
+
+ /* A list of permissions */
+ /* A list of channel to peer bindings */
+
+ char* software;
+
+ tnet_turn_channel_bindings_L_t *channel_bindings;
+ tnet_turn_permissions_L_t *permissions;
+}
+tnet_turn_allocation_t;
+typedef tsk_list_t tnet_turn_allocations_L_t; /**< List of @ref tnet_turn_allocation_t elements. */
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_permission_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_binding_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_allocation_def_t;
+
+//#if defined(__SYMBIAN32__) || ANDROID /* Forward declaration */
+struct tnet_nat_context_s;
+//#endif
+
+tnet_turn_allocation_id_t tnet_turn_allocate(const struct tnet_nat_context_s* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type);
+int tnet_turn_allocation_refresh(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation);
+int tnet_turn_unallocate(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation);
+tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer);
+int tnet_turn_channel_refresh(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind);
+int tnet_turn_channel_senddata(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication);
+int tnet_turn_add_permission(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout);
+
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_H */
+
diff --git a/tinyNET/src/turn/tnet_turn_attribute.c b/tinyNET/src/turn/tnet_turn_attribute.c
new file mode 100644
index 0000000..0bc55ad
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.c
@@ -0,0 +1,649 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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_attribute.c
+ * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_turn_attribute.h"
+
+#include "../stun/tnet_stun.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_debug.h"
+
+#include <string.h>
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number)
+{
+ return tsk_object_new(tnet_turn_attribute_channelnum_def_t, number);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime)
+{
+ return tsk_object_new(tnet_turn_attribute_lifetime_def_t, lifetime);
+}
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_xpeer_addr_def_t, payload, payload_size);
+}
+
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null()
+{
+ return tnet_turn_attribute_xpeer_addr_create(tsk_null, 0);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.4. DATA */
+tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_data_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_xrelayed_addr_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R)
+{
+ return tsk_object_new(tnet_turn_attribute_even_port_def_t, R);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol)
+{
+ return tsk_object_new(tnet_turn_attribute_reqtrans_def_t, protocol);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create()
+{
+ return tsk_object_new(tnet_turn_attribute_dontfrag_def_t);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_restoken_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_attribute_t* tnet_turn_attribute_deserialize(tnet_stun_attribute_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size)
+{
+ tnet_stun_attribute_t *attribute = tsk_null;
+ const uint8_t* dataPtr = payload;
+
+ /* Attribute Value
+ */
+
+ switch(type)
+ {
+ /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+ case stun_channel_number:
+ {
+ uint32_t number = tnet_htonl_2(dataPtr);
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_channelnum_create(number);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+ case stun_lifetime:
+ {
+ uint32_t lifetime = tnet_htonl_2(dataPtr);
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_lifetime_create(lifetime);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+ case stun_xor_peer_address:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.4. DATA */
+ case stun_data:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+ case stun_xor_relayed_address:
+ {
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_xrelayed_addr_create(dataPtr, length);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+ case stun_even_port:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+ case stun_requested_transport:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+ case stun_dont_fragment:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+ case stun_reservation_token:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ default:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+ }
+
+ if(!attribute){
+ /* Create default */
+ attribute = tnet_stun_attribute_create();
+ }
+
+ return attribute;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_attribute_serialize(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output)
+{
+ if(!attribute || !output){
+ return -1;
+ }
+
+ /* Attribute Value
+ */
+
+ switch(attribute->type){
+ /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+ case stun_channel_number:
+ {
+ tnet_turn_attribute_channelnum_t *number = (tnet_turn_attribute_channelnum_t*)attribute;
+ tsk_buffer_append(output, &(number->number), 2);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+ case stun_lifetime:
+ {
+ tnet_turn_attribute_lifetime_t *lifetime = (tnet_turn_attribute_lifetime_t*)attribute;
+ tsk_buffer_append(output, &(lifetime->value), 4);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+ case stun_xor_peer_address:
+ {
+ tnet_turn_attribute_xpeer_addr_t* xpeer = (tnet_turn_attribute_xpeer_addr_t*)attribute;
+ if(xpeer){
+ if(xpeer->family == stun_ipv4){
+ uint8_t pad = 0x00;
+ tsk_buffer_append(output, &pad, 1);
+ tsk_buffer_append(output, &xpeer->family, 1);
+ tsk_buffer_append(output, &xpeer->xport, 2);
+ tsk_buffer_append(output, xpeer->xaddress, 4);
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:XOR-PEER-ADDRESS ==> IPV6 - NOT IMPLEMENTED");
+ return -3;
+ }
+ }
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.4. DATA */
+ case stun_data:
+ {
+ tnet_turn_attribute_data_t *data = (tnet_turn_attribute_data_t*)attribute;
+ if(data->value){
+ tsk_buffer_append(output, data->value->data, data->value->size);
+ }
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+ case stun_xor_relayed_address:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:XOR-RELAYED-ADDRESS ==> NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+ case stun_even_port:
+ {
+ tnet_turn_attribute_even_port_t *even_port = (tnet_turn_attribute_even_port_t*)attribute;
+ uint8_t value = (even_port->R << 7);
+ tsk_buffer_append(output, &(value), 1);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+ case stun_requested_transport:
+ {
+ tnet_turn_attribute_reqtrans_t *reqtrans = (tnet_turn_attribute_reqtrans_t*)attribute;
+ tsk_buffer_append(output, &(reqtrans->protocol), 1);
+ tsk_buffer_append(output, &(reqtrans->rffu), 3);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+ case stun_dont_fragment:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:DONT-FRAGMENT ==> NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+ case stun_reservation_token:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:TOKEN ==> NOT IMPLEMENTED");
+ return -3;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_channelnum_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_channelnum_t *attribute = self;
+ if(attribute){
+#if defined (__GNUC__)
+ attribute->number = (uint16_t)(va_arg(*app, unsigned));
+#else
+ attribute->number = (va_arg(*app, uint16_t));
+#endif
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_channel_number;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 2;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_channelnum_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_channelnum_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_channelnum_def_s =
+{
+ sizeof(tnet_turn_attribute_channelnum_t),
+ tnet_turn_attribute_channelnum_ctor,
+ tnet_turn_attribute_channelnum_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t = &tnet_turn_attribute_channelnum_def_s;
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.2. LIFETIME]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_lifetime_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_lifetime_t *attribute = self;
+ if(attribute){
+ attribute->value = /*tnet_htonl*/(va_arg(*app, uint32_t));
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_lifetime;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_lifetime_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_lifetime_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_lifetime_def_s =
+{
+ sizeof(tnet_turn_attribute_lifetime_t),
+ tnet_turn_attribute_lifetime_ctor,
+ tnet_turn_attribute_lifetime_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t = &tnet_turn_attribute_lifetime_def_s;
+
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_xpeer_addr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_xpeer_addr_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ }
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_peer_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_xpeer_addr_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_xpeer_addr_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_xpeer_addr_def_s =
+{
+ sizeof(tnet_turn_attribute_xpeer_addr_t),
+ tnet_turn_attribute_xpeer_addr_ctor,
+ tnet_turn_attribute_xpeer_addr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t = &tnet_turn_attribute_xpeer_addr_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.4. DATA]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_data_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_data_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ attribute->value = tsk_buffer_create(payload, payload_size);
+ }
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_data;
+ TNET_STUN_ATTRIBUTE(attribute)->length = (uint16_t)payload_size;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_data_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_data_t *attribute = self;
+ if(attribute){
+ TSK_OBJECT_SAFE_FREE(attribute->value);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_data_def_s =
+{
+ sizeof(tnet_turn_attribute_data_t),
+ tnet_turn_attribute_data_ctor,
+ tnet_turn_attribute_data_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_data_def_t = &tnet_turn_attribute_data_def_s;
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_xrelayed_addr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ const uint8_t *payloadPtr = (const uint8_t*)payload;
+ payloadPtr += 1; /* Ignore first 8bits */
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_relayed_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+
+ attribute->family = (tnet_stun_addr_family_t)(*(payloadPtr++));
+
+ attribute->xport = tnet_ntohs_2(payloadPtr);
+ attribute->xport ^= 0x2112;
+ payloadPtr+=2;
+
+ { /*=== Compute IP address */
+ tsk_size_t addr_size = (attribute->family == stun_ipv6) ? 16 : (attribute->family == stun_ipv4 ? 4 : 0);
+ if(addr_size){
+ tsk_size_t i;
+ uint32_t addr;
+
+ for(i=0; i<addr_size; i+=4){
+ addr = tnet_htonl_2(payloadPtr);
+ addr ^= TNET_STUN_MAGIC_COOKIE;
+ memcpy(&attribute->xaddress[i], &addr, 4);
+ payloadPtr+=4;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+ }
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_xrelayed_addr_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_xrelayed_addr_def_s =
+{
+ sizeof(tnet_turn_attribute_xrelayed_addr_t),
+ tnet_turn_attribute_xrelayed_addr_ctor,
+ tnet_turn_attribute_xrelayed_addr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t = &tnet_turn_attribute_xrelayed_addr_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.6. EVEN-PORT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_even_port_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_even_port_t *attribute = self;
+ if(attribute){
+ attribute->R = va_arg(*app, unsigned);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_even_port;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 1;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_even_port_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_even_port_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_even_port_def_s =
+{
+ sizeof(tnet_turn_attribute_even_port_t),
+ tnet_turn_attribute_even_port_ctor,
+ tnet_turn_attribute_even_port_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_even_port_def_t = &tnet_turn_attribute_even_port_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_reqtrans_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_reqtrans_t *attribute = self;
+ if(attribute){
+ attribute->protocol = va_arg(*app, tnet_proto_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_requested_transport;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_reqtrans_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_reqtrans_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_reqtrans_def_s =
+{
+ sizeof(tnet_turn_attribute_reqtrans_t),
+ tnet_turn_attribute_reqtrans_ctor,
+ tnet_turn_attribute_reqtrans_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t = &tnet_turn_attribute_reqtrans_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_dontfrag_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_dontfrag_t *attribute = self;
+ if(attribute){
+ //const void *payload = va_arg(*app, const void*);
+ //tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_dont_fragment;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_dontfrag_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_dontfrag_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_dontfrag_def_s =
+{
+ sizeof(tnet_turn_attribute_dontfrag_t),
+ tnet_turn_attribute_dontfrag_ctor,
+ tnet_turn_attribute_dontfrag_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t = &tnet_turn_attribute_dontfrag_def_s;
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_restoken_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_restoken_t *attribute = self;
+ if(attribute){
+ //--const void *payload = va_arg(*app, const void*);
+ //--tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_reservation_token;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_restoken_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_restoken_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_restoken_def_s =
+{
+ sizeof(tnet_turn_attribute_restoken_t),
+ tnet_turn_attribute_restoken_ctor,
+ tnet_turn_attribute_restoken_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_restoken_def_t = &tnet_turn_attribute_restoken_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_attribute.h b/tinyNET/src/turn/tnet_turn_attribute.h
new file mode 100644
index 0000000..8a1915e
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.h
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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_attribute.h
+ * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_ATTRIBUTE_H
+#define TNET_TURN_ATTRIBUTE_H
+
+#include "tinynet_config.h"
+#include "tnet_proto.h"
+#include "stun/tnet_stun_attribute.h"
+
+TNET_BEGIN_DECLS
+
+typedef tnet_stun_attribute_t tnet_turn_attribute_t;
+
+/* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | RFFU = 0 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_attribute_channelnum_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint16_t number;
+ uint16_t rffu;
+}
+tnet_turn_attribute_channelnum_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.2. LIFETIME
+*/
+typedef struct tnet_turn_attribute_lifetime_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint32_t value;
+}
+tnet_turn_attribute_lifetime_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS
+*/
+typedef struct tnet_turn_attribute_xpeer_addr_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tnet_stun_addr_family_t family;
+ uint16_t xport;
+ uint8_t xaddress[16];
+}
+tnet_turn_attribute_xpeer_addr_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.4. DATA
+*/
+typedef struct tnet_turn_attribute_data_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tsk_buffer_t* value;
+}
+tnet_turn_attribute_data_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_data_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS
+*/
+typedef struct tnet_turn_attribute_xrelayed_addr_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tnet_stun_addr_family_t family;
+ uint16_t xport;
+ uint8_t xaddress[16];
+}
+tnet_turn_attribute_xrelayed_addr_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT
+*/
+typedef struct tnet_turn_attribute_even_port_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+/*
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |R| RFFU |
+ +-+-+-+-+-+-+-+-+
+*/
+ unsigned R:1;
+ unsigned rffu:7;
+}
+tnet_turn_attribute_even_port_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_even_port_def_t;
+
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_attribute_reqtrans_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+/*
+ draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Protocol | RFFU |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+ tnet_proto_t protocol;
+ uint8_t rffu[3];
+}
+tnet_turn_attribute_reqtrans_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t;
+
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT
+*/
+typedef struct tnet_turn_attribute_dontfrag_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+}
+tnet_turn_attribute_dontfrag_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN
+*/
+typedef struct tnet_turn_attribute_restoken_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint8_t value[8];
+}
+tnet_turn_attribute_restoken_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_restoken_def_t;
+
+
+tnet_stun_attribute_t* tnet_turn_attribute_deserialize(tnet_stun_attribute_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size);
+int tnet_turn_attribute_serialize(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output);
+
+tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number);
+tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime);
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null();
+tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R);
+tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol);
+tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create();
+tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size);
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_ATTRIBUTE_H */
+
diff --git a/tinyNET/src/turn/tnet_turn_message.c b/tinyNET/src/turn/tnet_turn_message.c
new file mode 100644
index 0000000..90372c3
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.c
@@ -0,0 +1,170 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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_message.c
+ * @brief Traversal Using Relays around NAT (TURN) messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_turn_message.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+
+#include <string.h>
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data)
+{
+ return tsk_object_new(tnet_turn_channel_data_def_t, number, length, data);
+}
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create_null()
+{
+ return tnet_turn_channel_data_create(0, 0, tsk_null);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message)
+{
+ tsk_buffer_t *output = 0;
+
+ if(!message) goto bail;
+
+ output = tsk_buffer_create_null();
+
+ /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / Application Data /
+ / /
+ | |
+ | +-------------------------------+
+ | |
+ +-------------------------------+
+ */
+
+ /* Channel Number
+ */
+ {
+ uint16_t number = tnet_htons(message->chanel_number);
+ tsk_buffer_append(output, &(number), 2);
+ }
+
+ /* Length
+ */
+ {
+ uint16_t length = tnet_htons(message->length);
+ tsk_buffer_append(output, &(length), 2);
+ }
+
+ /* Application Data
+ */
+ {
+ tsk_buffer_append(output, message->data, message->length);
+
+ /* === Padding:
+ Over stream transports, the ChannelData message MUST be padded to a
+ multiple of four bytes in order to ensure the alignment of subsequent
+ messages. The padding is not reflected in the length field of the
+ ChannelData message, so the actual size of a ChannelData message
+ (including padding) is (4 + Length) rounded up to the nearest
+ multiple of 4. Over UDP, the padding is not required but MAY be included.
+ */
+ if(message->length%4)
+ {
+ static uint32_t zeros = 0x00000000;
+ tsk_buffer_append(output, &zeros, 4-(message->length%4));
+ }
+ }
+
+bail:
+ return output;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// TURN CHANNEL-DATA message object definition
+//
+static tsk_object_t* tnet_turn_channel_data_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_channel_data_t *message = self;
+ if(message){
+ const void* data;
+
+#if defined(__GNUC__)
+ message->chanel_number = (uint16_t)va_arg(*app, unsigned);
+ message->length = (uint16_t)va_arg(*app, unsigned);
+#else
+ message->chanel_number = va_arg(*app, uint16_t);
+ message->length = va_arg(*app, uint16_t);
+#endif
+ data = va_arg(*app, const void*);
+
+ if(data && message->length){
+ if((message->data = tsk_calloc(message->length, sizeof(uint8_t)))){
+ memcpy(message->data, data, message->length);
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_channel_data_dtor(tsk_object_t * self)
+{
+ tnet_turn_channel_data_t *message = self;
+ if(message){
+ TSK_FREE(message->data);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_channel_data_def_s =
+{
+ sizeof(tnet_turn_channel_data_t),
+ tnet_turn_channel_data_ctor,
+ tnet_turn_channel_data_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_channel_data_def_t = &tnet_turn_channel_data_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_message.h b/tinyNET/src/turn/tnet_turn_message.h
new file mode 100644
index 0000000..1bd1714
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.h
@@ -0,0 +1,75 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.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_message.h
+ * @brief Traversal Using Relays around NAT (TURN) messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_MESSAGE_H
+#define TNET_TURN_MESSAGE_H
+
+#include "../tinynet_config.h"
+
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_turn_group
+ * TURN channel data message as per draft-ietf-behave-turn-16 subclause 11.4.
+*/
+typedef struct tnet_turn_channel_data_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / Application Data /
+ / /
+ | |
+ | +-------------------------------+
+ | |
+ +-------------------------------+
+ */
+ uint16_t chanel_number;
+ uint16_t length;
+ void* data;
+}
+tnet_turn_channel_data_t;
+
+tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message);
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data);
+tnet_turn_channel_data_t* tnet_turn_channel_data_create_null();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_data_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_MESSAGE_H */
OpenPOWER on IntegriCloud