doubango/tinyNET/src/stun/tnet_stun_message.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_stun_message.c
 // * @brief STUN2 (RFC 5389) message parser.
 // *
 // * @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
 // *
 //
 // */
 //#include "tnet_stun_message.h"
 //
 //#include "tnet_stun.h"
 //
 //#include "../tnet_types.h"
 //#include "../tnet_endianness.h"
 //#include "../turn/tnet_turn_attribute.h"
 //#include "stun/tnet_stun_types.h"
 //
 //#include "tsk_memory.h"
 //#include "tsk_hmac.h"
 //#include "tsk_string.h"
 //#include "tsk_ppfcs32.h"
 //
 //#include <string.h>
 //
 //static int __pred_find_attribute_by_type(const tsk_list_item_t *item, const void *att_type)
 //{
 //    if(item && item->data) {
 //        tnet_stun_attr_t *att = item->data;
 //        tnet_stun_attr_type_t type = *((tnet_stun_attr_type_t*)att_type);
 //        return (att->type - type);
 //    }
 //    return -1;
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Creates new STUN message.
 //* @retval @ref tnet_stun_pkt_t object.
 //* @sa tnet_stun_message_create_null.
 //*/
 //
 //tnet_stun_pkt_t* tnet_stun_message_create(const char* username, const char* password)
 //{
 //    return tsk_object_new(tnet_stun_message_def_t, username, password);
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Creates new STUN message.
 //* @retval @ref tnet_stun_pkt_t object.
 //* @sa tnet_stun_message_create.
 //*/
 //tnet_stun_pkt_t* tnet_stun_message_create_null()
 //{
 //    return tnet_stun_message_create(tsk_null, tsk_null);
 //}
 //
 //#define SERIALIZE_N_ADD_ATTRIBUTE(att_name, payload, payload_size) \
 //		attribute = (tnet_stun_attr_t *)tnet_stun_attribute_##att_name##_create(payload, payload_size); \
 //		tnet_stun_attribute_serialize(attribute, output); \
 //		tnet_stun_attribute_pad(attribute, output); \
 //		TSK_OBJECT_SAFE_FREE(attribute);
 //
 ///**@ingroup tnet_stun_group
 // * Serializes a STUN message as binary data.
 // * @param [in,out]	self	The STUN message to serialize.
 // * @retval	A buffer holding the binary data (result) if serialization succeed and zero otherwise.
 //**/
 //tsk_buffer_t* tnet_stun_pkt_serialize(const tnet_stun_pkt_t *self)
 //{
 //    tsk_buffer_t *output = 0;
 //    tnet_stun_attr_t *attribute;
 //    unsigned compute_integrity = self->integrity;
 //
 //    if(!self) {
 //        goto bail;
 //    }
 //
 //    output = tsk_buffer_create_null();
 //
 //    /*	RFC 5389 - 6.  STUN Message Structure
 //       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
 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //      |0 0|     STUN Message Type     |         Message Length        |
 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //      |                         Magic Cookie                          |
 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //      |                                                               |
 //      |                     Transaction ID (96 bits)                  |
 //      |                                                               |
 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 //    */
 //
 //    /* STUN Message Type
 //    */
 //    {
 //        uint16_t type = tnet_htons(self->type);
 //        tsk_buffer_append(output, &(type), 2);
 //    }
 //
 //    /* Message Length ==> Will be updated after attributes have been added. */
 //    {
 //        static const uint16_t length = 0;
 //        tsk_buffer_append(output, &(length), 2);
 //    }
 //
 //    /* Magic Cookie
 //    */
 //    {
 //        uint32_t cookie = tnet_htonl(self->cookie);
 //        tsk_buffer_append(output, &(cookie), 4);
 //    }
 //
 //
 //    /* Transaction ID (96 bits==>16bytes)
 //    */
 //    tsk_buffer_append(output, self->transac_id, TNET_STUN_TRANSACID_SIZE);
 //
 //    /* DONT-FRAGMENT
 //    */
 //    if(self->dontfrag) {
 //        /*attribute = (tnet_stun_attr_t *)tnet_turn_attribute_dontfrag_create();
 //        tnet_stun_attribute_serialize(attribute, output);
 //        TSK_OBJECT_SAFE_FREE(attribute);*/
 //    }
 //
 //    /* AUTHENTICATION */
 //    if(self->realm && self->nonce) { // long term
 //        SERIALIZE_N_ADD_ATTRIBUTE(realm, self->realm, tsk_strlen(self->realm));
 //        SERIALIZE_N_ADD_ATTRIBUTE(nonce, self->nonce, tsk_strlen(self->nonce));
 //
 //        compute_integrity = !self->nointegrity;
 //    }
 //    else if(self->password) { // short term
 //        compute_integrity = !self->nointegrity;
 //    }
 //
 //    if(compute_integrity && self->username) {
 //        SERIALIZE_N_ADD_ATTRIBUTE(username, self->username, tsk_strlen(self->username));
 //    }
 //
 //    /*=== Attributes === */
 //    {
 //        tsk_list_item_t *item;
 //        tsk_list_foreach(item, self->attributes) {
 //            attribute = item->data;
 //            tnet_stun_attribute_serialize(attribute, output);
 //            tnet_stun_attribute_pad(attribute, output);
 //        }
 //    }
 //
 //    /* Message Length: The message length MUST contain the size, in bytes, of the message
 //    					not including the 20-byte STUN header.
 //    */
 //    {
 //        // compute length for 'MESSAGE-INTEGRITY'
 //        // will be computed again to store the correct value
 //        uint16_t length = (output->size) - kStunAttrHdrSizeInOctets;
 //        if(self->fingerprint) {
 //            length += (2/* Type */ + 2 /* Length */+ 4 /* FINGERPRINT VALUE*/);
 //        }
 //
 //        if(compute_integrity) {
 //            length += (2/* Type */ + 2 /* Length */+ TSK_SHA1_DIGEST_SIZE /* INTEGRITY VALUE*/);
 //        }
 //
 //        *(((uint16_t*)output->data)+1)  = tnet_htons(length);
 //    }
 //
 //    /* MESSAGE-INTEGRITY */
 //    if(compute_integrity) {
 //        /* RFC 5389 - 15.4.  MESSAGE-INTEGRITY
 //           The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of the STUN message.
 //
 //           For long-term credentials ==> key = MD5(username ":" realm ":" SASLprep(password))
 //           For short-term credentials ==> key = SASLprep(password)
 //        */
 //
 //        tsk_sha1digest_t hmac;
 //
 //        if(self->username && self->realm && self->password) { // long term
 //            char* keystr = tsk_null;
 //            tsk_md5digest_t md5;
 //            tsk_sprintf(&keystr, "%s:%s:%s", self->username, self->realm, self->password);
 //            TSK_MD5_DIGEST_CALC(keystr, tsk_strlen(keystr), md5);
 //            hmac_sha1digest_compute(output->data, output->size, (const char*)md5, TSK_MD5_DIGEST_SIZE, hmac);
 //
 //            TSK_FREE(keystr);
 //        }
 //        else { // short term
 //            hmac_sha1digest_compute(output->data, output->size, self->password, tsk_strlen(self->password), hmac);
 //        }
 //
 //        SERIALIZE_N_ADD_ATTRIBUTE(integrity, hmac, TSK_SHA1_DIGEST_SIZE);
 //    }
 //
 //    // LENGTH
 //    *(((uint16_t*)output->data) + 1)  = tnet_htons((output->size - kStunAttrHdrSizeInOctets + (self->fingerprint ? 8 : 0)));
 //
 //    /* FINGERPRINT */
 //    if(self->fingerprint) { //JINGLE_ICE
 //        /*	RFC 5389 - 15.5.  FINGERPRINT
 //        	The FINGERPRINT attribute MAY be present in all STUN messages.  The
 //        	value of the attribute is computed as the CRC-32 of the STUN message
 //        	up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
 //        	the 32-bit value 0x5354554e
 //        */
 //        uint32_t fingerprint = tsk_pppfcs32(TSK_PPPINITFCS32, output->data, output->size);
 //        fingerprint ^= 0x5354554e;
 //        fingerprint = tnet_htonl(fingerprint);
 //
 //        attribute = (tnet_stun_attr_t *)tnet_stun_attribute_fingerprint_create(fingerprint);
 //        tnet_stun_attribute_serialize(attribute, output);
 //        TSK_OBJECT_SAFE_FREE(attribute);
 //    }
 //
 //bail:
 //    return output;
 //}
 //
 //
 ///**@ingroup tnet_stun_group
 // *
 // * Deserializes a STUN message from binary data.
 // *
 // * @param [in,out]	data	A pointer to the binary data.
 // * @param	size			The size of the binary data.
 // *
 // * @retval	A STUN message if deserialization succeed or NULL otherwise.
 //**/
 //tnet_stun_pkt_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size)
 //{
 //    tnet_stun_pkt_t *message = 0;
 //    uint8_t* dataPtr, *dataEnd;
 //
 //
 //    if(!data || (size  < kStunAttrHdrSizeInOctets) || !TNET_STUN_BUFF_IS_STUN2(data, size)) {
 //        goto bail;
 //    }
 //
 //    dataPtr = (uint8_t*)data;
 //    dataEnd = (dataPtr + size);
 //
 //    message = tnet_stun_message_create_null();
 //
 //    /* Message Type
 //    */
 //    message->type = (tnet_stun_pkt_type_t)tnet_ntohs_2(dataPtr);
 //    dataPtr += 2;
 //
 //    /* Message Length
 //    */
 //    message->length = tnet_ntohs_2(dataPtr);
 //    dataPtr += 2;
 //
 //    /* Check message validity
 //    */
 //    if((message->length + kStunAttrHdrSizeInOctets) != size) {
 //        TSK_OBJECT_SAFE_FREE(message);
 //        goto bail;
 //    }
 //
 //    /* Magic Cookie
 //    	==> already set by the constructor and checked by @ref TNET_IS_STUN2
 //    */
 //    dataPtr += 4;
 //
 //    /* Transaction ID
 //    */
 //    memcpy(message->transac_id, dataPtr, TNET_STUN_TRANSACID_SIZE);
 //    dataPtr += TNET_STUN_TRANSACID_SIZE;
 //
 //    /*	== Parse attributes
 //    */
 //    while(dataPtr < dataEnd) {
 //        tnet_stun_attr_t *attribute = tnet_stun_attribute_deserialize(dataPtr, (dataEnd - dataPtr));
 //        if(attribute) {
 //            tsk_size_t att_size = (attribute->length + 2 /* Type*/ + 2/* Length */);
 //            att_size += (att_size & 0x03) ? 4-(att_size & 0x03) : 0; // Skip zero bytes used to pad the attribute.
 //
 //            dataPtr += att_size;
 //            tsk_list_push_back_data(message->attributes, (void**)&attribute);
 //
 //            continue;
 //        }
 //        else {
 //            continue;
 //        }
 //    }
 //
 //bail:
 //    return message;
 //}
 //
 ///**@ingroup tnet_stun_group
 //*/
 //tsk_bool_t tnet_stun_message_has_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
 //{
 //    return (tnet_stun_message_get_attribute(self, type) != tsk_null);
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Adds an attribute to a STUN message.
 //* @param self The STUN message into which to add the attribute.
 //* @param attribute The attribute to add.
 //* @retval Zero if succeed and non-zero error code otherwise.
 //*/
 //int tnet_stun_message_add_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_t** attribute)
 //{
 //    if(self && attribute && *attribute) {
 //        tsk_list_push_back_data(self->attributes, (void**)attribute);
 //        return 0;
 //    }
 //    return -1;
 //}
 //
 ///**@ingroup tnet_stun_group
 //*/
 //int tnet_stun_message_remove_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
 //{
 //    if(self && self->attributes) {
 //        tsk_list_remove_item_by_pred(self->attributes, __pred_find_attribute_by_type, &type);
 //    }
 //    return 0;
 //}
 //
 //
 ///**@ingroup tnet_stun_group
 //* Gets a STUN attribute from a message.
 //* @param self The message from which to get the attribute.
 //* @param type The type of the attribute to retrieve.
 //* @retval @ref tnet_stun_attr_t object if found and NULL otherwise.
 //*/
 //const tnet_stun_attr_t* tnet_stun_message_get_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type)
 //{
 //    tnet_stun_attr_t* attribute;
 //
 //    if(self && !TSK_LIST_IS_EMPTY(self->attributes)) {
 //        tsk_list_item_t *item;
 //        tsk_list_foreach(item, self->attributes) {
 //            if((attribute = item->data) && attribute->type == type) {
 //                return attribute;
 //            }
 //        }
 //    }
 //    return 0;
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Gets the STUN error-code attribute value from the message.
 //* @param self The STUN message from which to get the error code.
 //* @retval The error code if the message contain such attribute or -1 otherwise.
 //*/
 //short tnet_stun_message_get_errorcode(const tnet_stun_pkt_t *self)
 //{
 //    const tnet_stun_attribute_errorcode_t* error = (const tnet_stun_attribute_errorcode_t*)tnet_stun_message_get_attribute(self, stun_error_code);
 //    if(error) {
 //        return  ((error->_class*100) + error->number);
 //    }
 //    return -1;
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Gets the STUN @b realm attribute value from the message.
 //* @param self The STUN message from which to get the @b realm.
 //* @retval The @b realm as a string pointer code if the message contain such attribute or NULL otherwise.
 //*/
 //const char* tnet_stun_message_get_realm(const tnet_stun_pkt_t *self)
 //{
 //    const tnet_stun_attribute_realm_t* realm = (const tnet_stun_attribute_realm_t*)tnet_stun_message_get_attribute(self, stun_realm);
 //    if(realm) {
 //        return realm->value;
 //    }
 //    return 0;
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Gets the STUN @b nonce attribute value from the message.
 //* @param self The STUN message from which to get the @b nonce.
 //* @retval The @b nonce as a string pointer code if the message contain such attribute or NULL otherwise.
 //*/
 //const char* tnet_stun_message_get_nonce(const tnet_stun_pkt_t *self)
 //{
 //    const tnet_stun_attribute_nonce_t* nonce = (const tnet_stun_attribute_nonce_t*)tnet_stun_message_get_attribute(self, stun_nonce);
 //    if(nonce) {
 //        return nonce->value;
 //    }
 //    return 0;
 //}
 //
 ///**@ingroup tnet_stun_group
 //* Gets the STUN @b lifetime attribute value from the message.
 //* @param self The STUN message from which to get the @b lifetime.
 //* @retval The @b lifetime (any positive value) if the message contain such attribute or -1 otherwise.
 //*/
 //int32_t tnet_stun_message_get_lifetime(const tnet_stun_pkt_t *self)
 //{
 //    /*const tnet_turn_attribute_lifetime_t* lifetime = (const tnet_turn_attribute_lifetime_t*)tnet_stun_message_get_attribute(self, stun_lifetime);
 //    if(lifetime) {
 //        return lifetime->value;
 //    }*/
 //    return -1;
 //}
 //
 ///**@ingroup tnet_stun_group
 //*/
 //tsk_bool_t tnet_stun_utils_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2)
 //{
 //    tsk_size_t i;
 //    static const tsk_size_t size = sizeof(tnet_stun_transac_id_t);
 //    for(i = 0; i < size; i++) {
 //        if(id1[i] != id2[i]) {
 //            return tsk_false;
 //        }
 //    }
 //    return tsk_true;
 //}
 //
 //
 //
 //
 //
 //
 ////=================================================================================================
 ////	STUN2 MESSAGE object definition
 ////
 //static tsk_object_t* tnet_stun_message_ctor(tsk_object_t * self, va_list * app)
 //{
 //    tnet_stun_pkt_t *message = self;
 //    if(message) {
 //        message->username = tsk_strdup(va_arg(*app, const char*));
 //        message->password = tsk_strdup(va_arg(*app, const char*));
 //
 //        message->cookie = kStunMagicCookieLong;
 //        message->attributes = tsk_list_create();
 //
 //        message->fingerprint = 1;
 //        message->integrity = 0;
 //
 //        {
 //            // Create random transaction id
 //            int i;
 //            for(i = 0; i < sizeof(message->transac_id)/sizeof(message->transac_id[0]); ++i) {
 //                message->transac_id[i] = rand();
 //            }
 //        }
 //    }
 //    return self;
 //}
 //
 //static tsk_object_t* tnet_stun_message_dtor(tsk_object_t * self)
 //{
 //    tnet_stun_pkt_t *message = self;
 //    if(message) {
 //        TSK_FREE(message->username);
 //        TSK_FREE(message->password);
 //        TSK_FREE(message->realm);
 //        TSK_FREE(message->nonce);
 //
 //        TSK_OBJECT_SAFE_FREE(message->attributes);
 //    }
 //
 //    return self;
 //}
 //
 //static const tsk_object_def_t tnet_stun_message_def_s = {
 //    sizeof(tnet_stun_pkt_t),
 //    tnet_stun_message_ctor,
 //    tnet_stun_message_dtor,
 //    tsk_null,
 //};
 //const tsk_object_def_t *tnet_stun_message_def_t = &tnet_stun_message_def_s;
 //