diff options
author | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
---|---|---|
committer | Mamadou DIOP <bossiel@yahoo.fr> | 2015-08-17 01:56:35 +0200 |
commit | 631fffee8a28b1bec5ed1f1d26a20e0135967f99 (patch) | |
tree | 74afe3bf3efe15aa82bcd0272b2b0f4d48c2d837 /tinyNET/src/stun | |
parent | 7908865936604036e6f200f1b5e069f8752f3a3a (diff) | |
download | doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.zip doubango-631fffee8a28b1bec5ed1f1d26a20e0135967f99.tar.gz |
-
Diffstat (limited to 'tinyNET/src/stun')
-rw-r--r-- | tinyNET/src/stun/AStyle.sh | 1 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun.c | 440 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun.h | 127 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_attr.c | 651 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_attr.h | 81 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_attribute.c | 1176 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_attribute.h | 356 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_binding.c | 127 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_binding.h | 67 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_message.c | 495 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_message.h | 246 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_pkt.c | 751 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_pkt.h | 187 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_types.h | 373 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_utils.c | 201 | ||||
-rw-r--r-- | tinyNET/src/stun/tnet_stun_utils.h | 45 |
16 files changed, 5324 insertions, 0 deletions
diff --git a/tinyNET/src/stun/AStyle.sh b/tinyNET/src/stun/AStyle.sh new file mode 100644 index 0000000..9d81f4d --- /dev/null +++ b/tinyNET/src/stun/AStyle.sh @@ -0,0 +1 @@ +../../../thirdparties/win32/bin/AStyle.exe --style=k/r --lineend=linux --mode=c --add-brackets --break-closing-brackets --recursive "*.c" "*.h"
\ No newline at end of file diff --git a/tinyNET/src/stun/tnet_stun.c b/tinyNET/src/stun/tnet_stun.c new file mode 100644 index 0000000..d8566b2 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun.c @@ -0,0 +1,440 @@ +///* +//* 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.c +// * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete). +// * +// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> +// * +// +// */ +//#include "tnet_stun.h" +// +//#include "../tnet_nat.h" +//#include "../tnet_utils.h" +// +//#include "tsk_md5.h" +//#include "tsk_string.h" +//#include "tsk_memory.h" +//#include "tsk_buffer.h" +//#include "tsk_debug.h" +// +//#include <string.h> +// +///**@defgroup tnet_stun_group STUN2 (RFC 5389) implementation. +//*/ +// +// +///**@ingroup tnet_stun_group +//* Creates new @ref tnet_stun_binding_t object. +//*/ +//tnet_stun_binding_t* tnet_stun_binding_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_stun_binding_def_t, fd, socket_type, server_address, server_port, username, password); +//} +// +///**@ingroup tnet_stun_group +// * +// * Create generic STUN2 request with all mandatory headers and attributes. +// * +// * @param [in,out] binding The binding object from which to create the request. +// * +// * @retval STUN2 request if succeed and NULL otherwise. +//**/ +//tnet_stun_pkt_t *tnet_stun_create_request(const tnet_stun_binding_t* binding) +//{ +// tnet_stun_pkt_t *message = tnet_stun_message_create(binding->username, binding->password); +// +// if(message) { +// message->realm = tsk_strdup(binding->realm); +// message->nonce = tsk_strdup(binding->nonce); +// +// /* Set the request type (RFC 5389 defines only one type) */ +// message->type = stun_binding_request; +// +// { /* Create random transaction id */ +// tsk_istr_t random; +// tsk_md5digest_t digest; +// +// tsk_strrandom(&random); +// TSK_MD5_DIGEST_CALC(random, sizeof(random), digest); +// +// memcpy(message->transac_id, digest, TNET_STUN_TRANSACID_SIZE); +// } +// +// /* Add software attribute */ +// if(binding->software) { +// tnet_stun_attr_t* attribute = (tnet_stun_attr_t*)tnet_stun_attribute_software_create(binding->software, tsk_strlen(binding->software)); +// tnet_stun_message_add_attribute(message, &attribute); +// } +// } +// +// return message; +//} +// +//int tnet_stun_send_reliably(const tnet_stun_pkt_t* message) +//{ +// return -1; +//} +// +// +///**@ingroup tnet_stun_group +// * +// * Internal function to send a STUN message using unrealiable protocol such as UDP. +// * +// * +// * @param localFD The local file descriptor. +// * @param RTO The Retransmission TimeOut. +// * @param Rc The Number of retransmissions. +// * @param [in,out] message The message to send. +// * @param [in,out] server The destination STUN server. +// * +// * @return The response from the server or NULL if transport error. +//**/ +//tnet_stun_pkt_resp_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_pkt_t* message, struct sockaddr* server) +//{ +// /* RFC 5389 - 7.2.1. Sending over UDP +// STUN indications are not retransmitted; thus, indication transactions over UDP +// are not reliable. +// */ +// //int retransmit = (message->type == stun_binding_request); +// +// int ret = -1; +// uint16_t i, rto = RTO; +// struct timeval tv; +// fd_set set; +// +// tsk_buffer_t *buffer = tnet_stun_pkt_serialize(message); +// tnet_stun_pkt_resp_t *response = tsk_null; +// +// if(!buffer) { +// goto bail; +// } +// +// { +////#ifndef SIO_UDP_CONNRESET +////# ifndef IOC_VENDOR +////# define IOC_VENDOR 0x18000000 +////# endif +////# ifndef _WSAIOW +////# define _WSAIOW(x,y) (IOC_IN|(x)|(y)) +////# endif +////# define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12) +////#endif +//// DWORD dwBytesReturned = 0; +//// BOOL bNewBehavior = TRUE; +//// DWORD status; +//// +//// // disable new behavior using +//// // IOCTL: SIO_UDP_CONNRESET +//// status = WSAIoctl(localFD, SIO_UDP_CONNRESET, &bNewBehavior, sizeof(bNewBehavior), +//// NULL, 0, &dwBytesReturned, NULL, NULL); +// } +// +// tv.tv_sec = 0; +// tv.tv_usec = 0; +// +// /* RFC 5389 - 7.2.1. Sending over UDP +// A client SHOULD retransmit a STUN request message starting with an +// interval of RTO ("Retransmission TimeOut"), doubling after each +// retransmission. +// +// e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms +// */ +// for(i=0; i<Rc; i++) { +// tv.tv_sec += rto/1000; +// tv.tv_usec += (rto% 1000) * 1000; +// +// FD_ZERO(&set); +// FD_SET(localFD, &set); +// +// ret = tnet_sockfd_sendto(localFD, server, buffer->data, buffer->size); +// +// if((ret = select(localFD+1, &set, NULL, NULL, &tv))<0) { +// goto bail; +// } +// else if(ret == 0) { +// /* timeout */ +// TSK_DEBUG_INFO("STUN request timedout at %d", i); +// rto *= 2; +// continue; +// } +// else if(FD_ISSET(localFD, &set)) { +// /* there is data to read */ +// +// tsk_size_t len = 0; +// void* data = 0; +// +// TSK_DEBUG_INFO("STUN request got response"); +// +// /* Check how how many bytes are pending */ +// if((ret = tnet_ioctlt(localFD, FIONREAD, &len))<0) { +// goto bail; +// } +// +// if(len==0) { +// TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes"); +// continue; +// } +// +// /* Receive pending data */ +// data = tsk_calloc(len, sizeof(uint8_t)); +// if((ret = tnet_sockfd_recvfrom(localFD, data, len, 0, server))<0) { +// TSK_FREE(data); +// +// TSK_DEBUG_ERROR("Recving STUN dgrams failed with error code:%d", tnet_geterrno()); +// goto bail; +// } +// +// /* Parse the incoming response. */ +// response = tnet_stun_message_deserialize(data, (tsk_size_t)ret); +// TSK_FREE(data); +// +// if(response) { +// if(tnet_stun_transacid_cmp(message->transac_id, response->transac_id)) { +// /* Not same transaction id */ +// TSK_OBJECT_SAFE_FREE(response); +// continue; +// } +// } +// +// goto bail; +// } +// else { +// continue; +// } +// } +// +//bail: +// TSK_OBJECT_SAFE_FREE(buffer); +// +// return response; +//} +// +///**@ingroup tnet_stun_group +// * Internal function to send a STUN2 binding request over the network. +// * +// * @param [in,out] context The NAT context holding the user preferences. +// * @param [in,out] binding The STUN binding object used to create the message to send. +// * +// * @return Zero if succeed and non-zero error code otherwise. +//**/ +//int tnet_stun_send_bind(const tnet_nat_context_t* context, tnet_stun_binding_t *binding) +//{ +// int ret = -1; +// tnet_stun_pkt_resp_t *response = 0; +// tnet_stun_pkt_req_t *request = 0; +// +// +// goto stun_phase0; +// +// /* RFC 5389 - 10.2.1.1. First Request +// If the client has not completed a successful request/response +// transaction with the server (as identified by hostname, if the DNS +// procedures of Section 9 are used, else IP address if not), it SHOULD +// omit the USERNAME, MESSAGE-INTEGRITY, REALM, and NONCE attributes. +// In other words, the very first request is sent as if there were no +// authentication or message integrity applied. +// */ +//stun_phase0: { +// if(!(request = tnet_stun_create_request(binding))) { +// goto bail; +// } +// +// if(TNET_SOCKET_TYPE_IS_DGRAM(context->socket_type)) { +// response = tnet_stun_send_unreliably(binding->localFD, context->RTO, context->Rc, request, (struct sockaddr*)&binding->server); +// } +// +// if(response) { +// if(TNET_STUN_PKT_RESP_IS_ERROR(response)) { +// short code = tnet_stun_message_get_errorcode(response); +// const char* realm = tnet_stun_message_get_realm(response); +// const char* nonce = tnet_stun_message_get_nonce(response); +// +// if(code == 401 && realm && nonce) { +// if(!binding->nonce) { +// /* First time we get a nonce */ +// tsk_strupdate(&binding->nonce, nonce); +// tsk_strupdate(&binding->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_stun_send_bind(context, binding); +// } +// else { +// ret = -3; +// } +// } +// else { +// ret = -2; +// } +// } +// else { +// const tnet_stun_attr_t *attribute; +// if((attribute= tnet_stun_message_get_attribute(response, stun_xor_mapped_address))) { +// ret = 0; +// binding->xmaddr = tsk_object_ref((void*)attribute); +// } +// else if((attribute= tnet_stun_message_get_attribute(response, stun_mapped_address))) { +// ret = 0; +// binding->maddr = tsk_object_ref((void*)attribute); +// } +// } +// } +// } +// /* END OF stun_phase0 */ +// +//bail: +// TSK_OBJECT_SAFE_FREE(response); +// TSK_OBJECT_SAFE_FREE(request); +// +// return ret; +//} +// +///**@ingroup tnet_stun_group +// * +// * Public function to create a binding context. +// * +// * @param [in,out] nat_context The NAT context. +// * @param localFD The local file descriptor for which to create the binding context. +// * +// * @return A valid binding id if succeed and @ref kStunBindingInvalidId otherwise. If the returned id is valid then +// * the newly created binding will contain the server reflexive address associated to the local file descriptor. +//**/ +//tnet_stun_binding_id_t tnet_stun_bind(const tnet_nat_context_t* nat_context, tnet_fd_t localFD) +//{ +// tnet_stun_binding_id_t id = kStunBindingInvalidId; +// +// tnet_stun_binding_t *binding = 0; +// +// if(nat_context && localFD != TNET_INVALID_FD) { +// if(!(binding = tnet_stun_binding_create(localFD, nat_context->socket_type, nat_context->server_address, nat_context->server_port, nat_context->username, nat_context->password))) { +// goto bail; +// } +// +// if(tnet_stun_send_bind(nat_context, binding)) { +// TSK_OBJECT_SAFE_FREE(binding); +// goto bail; +// } +// +// id = binding->id; +// tsk_list_push_back_data(nat_context->stun_bindings, (void**)&binding); +// } +// +//bail: +// return id; +//} +// +///**@ingroup tnet_stun_group +// * Compares two transaction ids. +// * +// * @param id1 The first transaction identifier. +// * @param id2 The second transaction identifier. +// * +// * @return Zero if the two identifiers are equal and non-zero value otherwise. +//**/ +//int tnet_stun_transacid_cmp(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2) +//{ +// tsk_size_t i; +// for(i=0; i<sizeof(tnet_stun_transac_id_t); i++) { +// if(id1[i] != id2[i]) { +// return (id1[i] - id2[i]); +// } +// } +// return 0; +//} +// +// +// +// +// +// +// +// +// +// +////================================================================================================= +//// STUN2 BINDING object definition +//// +//static tsk_object_t* tnet_stun_binding_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_binding_t *binding = self; +// if(binding) { +// static tnet_stun_binding_id_t __binding_unique_id = 0; +// +// const char* server_address; +// tnet_port_t server_port; +// +// binding->id = ++__binding_unique_id; +// +// binding->localFD = va_arg(*app, tnet_fd_t); +// binding->socket_type = va_arg(*app, tnet_socket_type_t); +// +// server_address = tsk_strdup(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 +// +// binding->username = tsk_strdup(va_arg(*app, const char*)); +// binding->password = tsk_strdup(va_arg(*app, const char*)); +// +// if(server_address) { +// tnet_sockaddr_init(server_address, server_port, binding->socket_type, &binding->server); +// } +// +// binding->software = tsk_strdup(TNET_SOFTWARE); +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_binding_dtor(tsk_object_t * self) +//{ +// tnet_stun_binding_t *binding = self; +// if(binding) { +// TSK_FREE(binding->username); +// TSK_FREE(binding->password); +// TSK_FREE(binding->realm); +// TSK_FREE(binding->nonce); +// +// TSK_FREE(binding->software); +// +// TSK_OBJECT_SAFE_FREE(binding->maddr); +// TSK_OBJECT_SAFE_FREE(binding->xmaddr); +// } +// +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_binding_def_s = { +// sizeof(tnet_stun_binding_t), +// tnet_stun_binding_ctor, +// tnet_stun_binding_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_binding_def_t = &tnet_stun_binding_def_s; +// +// diff --git a/tinyNET/src/stun/tnet_stun.h b/tinyNET/src/stun/tnet_stun.h new file mode 100644 index 0000000..26f0def --- /dev/null +++ b/tinyNET/src/stun/tnet_stun.h @@ -0,0 +1,127 @@ +///* +//* 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.h +// * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete). +// * +// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> +// * +// +// */ +//#ifndef TNET_STUN_H +//#define TNET_STUN_H +// +//#include "tinynet_config.h" +//#include "stun/tnet_stun_message.h" +//#include "tnet_types.h" +//#include "tnet_socket.h" +// +//#include "tsk_object.h" +// +//TNET_BEGIN_DECLS +// +///**@ingroup tnet_stun_group +//*/ +////typedef uint64_t tnet_stun_binding_id_t; +///**@ingroup tnet_stun_group +// * @def kStunBindingInvalidId +// * STUN2 invalid binding id. +//**/ +///**@ingroup tnet_stun_group +// * @def TNET_STUN_IS_VALID_BINDING_ID +// * Checks the validity of the STUN @a id. +//**/ +//#define kStunBindingInvalidId 0 +//#define TNET_STUN_IS_VALID_BINDING_ID(id) (id != kStunBindingInvalidId) +// +///**@ingroup tnet_stun_group +// * Default port for both TCP and UDP protos as per RFC 5389 subclause 9. +//**/ +//#define TNET_STUN_TCP_UDP_DEFAULT_PORT 3478 +// +///**@ingroup tnet_stun_group +// * Default port for TLS protocol as per RFC 5389 subclause 9. +//**/ +//#define TNET_STUN_TLS_DEFAULT_PORT 5349 +// +// +///**@ingroup tnet_stun_group +// * STUN2 magic cookie value in network byte order as per RFC 5389 subclause 6. +//**/ +//#define kStunMagicCookieLong 0x2112A442 +// +///**@ingroup tnet_stun_group +// * STUN2 header size as per RFC 5389 subclause 6. +//**/ +//#define kStunAttrHdrSizeInOctets 20 +// +///**@ingroup tnet_stun_group +// * STUN2 binding context. +//**/ +//typedef struct tnet_stun_binding_s { +// TSK_DECLARE_OBJECT; +// +// //! A unique id to identify this binding. +// tnet_stun_binding_id_t id; +// +// //! The username to authenticate to the STUN server. +// char* username; +// //! The password to authenticate to the STUN server. +// char* password; +// //! The realm. +// char* realm; +// //! The nonce. +// char* nonce; +// //! The client name. +// char* software; +// //! Local file descriptor for which to get server reflexive address. +// tnet_fd_t localFD; +// //! The type of the bound socket. +// tnet_socket_type_t socket_type; +// //! The address of the STUN server. +// struct sockaddr_storage server; +// //! 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; +//} tnet_stun_binding_t; +// +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_binding_def_t; +///**@ingroup tnet_stun_group +// * List of @ref tnet_stun_binding_t elements. +//**/ +//typedef tsk_list_t tnet_stun_bindings_L_t; +// +////#if defined(__SYMBIAN32__) || ANDROID /* Forward declaration */ +//struct struct tnet_nat_ctx_s; +////#endif +// +//int tnet_stun_send_reliably(const tnet_stun_pkt_t* message); +//tnet_stun_pkt_resp_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_pkt_t* message, struct sockaddr* server); +//TINYNET_API tnet_stun_binding_id_t tnet_stun_bind(const struct struct tnet_nat_ctx_s* nat_context, tnet_fd_t localFD); +//int tnet_stun_transacid_cmp(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2); +// +//TNET_END_DECLS +// +// +//#endif /* TNET_STUN_H */ +// diff --git a/tinyNET/src/stun/tnet_stun_attr.c b/tinyNET/src/stun/tnet_stun_attr.c new file mode 100644 index 0000000..4c31c05 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_attr.c @@ -0,0 +1,651 @@ +/* Copyright (C) 2015 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stun/tnet_stun_attr.h" +#include "stun/tnet_stun_utils.h" + +#include "tnet_endianness.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +#define kWithoutPadding tsk_false +#define kWithPadding tsk_true + +#if !defined(PRINT_DESTROYED_MSG) +# define PRINT_DESTROYED_MSG 0 +#endif + +#define ALIGN_ON_32BITS(size_in_octes) if (((size_in_octes) & 3)) (size_in_octes) += (4 - ((size_in_octes) & 3)); +#define ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(p_buffer, size_in_octes) \ + if (((size_in_octes) & 3)) { \ + int c = (4 - ((size_in_octes) & 3)); \ + memset(p_buffer, 0, c); \ + (size_in_octes) += c; \ + } + +#define IS_ADDRESS_XOR(e_type) \ + (e_type == tnet_stun_attr_type_xor_mapped_address || e_type == tnet_stun_attr_type_xor_peer_address || e_type == tnet_stun_attr_type_xor_relayed_address) +#define IS_VDATA_UINT8(e_type) \ + (e_type == tnet_stun_attr_type_requested_transport) +#define IS_VDATA_UINT16(e_type) \ + (e_type == tnet_stun_attr_type_channel_number) +#define IS_VDATA_UINT32(e_type) \ + (e_type == tnet_stun_attr_type_fingerprint || e_type == tnet_stun_attr_type_lifetime || e_type == tnet_stun_attr_type_ice_priority || e_type == tnet_stun_attr_type_connection_id) +#define IS_VDATA_UINT64(e_type) \ + (e_type == tnet_stun_attr_type_ice_controlled || e_type == tnet_stun_attr_type_ice_controlling) + +static int _tnet_stun_attr_cmp(const tsk_object_t *_att1, const tsk_object_t *_att2) +{ + const tnet_stun_attr_t *pc_att1 = (const tnet_stun_attr_t *)_att1; + const tnet_stun_attr_t *pc_att2 = (const tnet_stun_attr_t *)_att2; + + return (int)(pc_att1 - pc_att2); +} + +static int _tnet_stun_attr_get_size_in_octetunits(const tnet_stun_attr_t* pc_self, tsk_bool_t with_padding, tsk_size_t* p_size) +{ + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + switch (pc_self->hdr.e_type) { + case tnet_stun_attr_type_mapped_address: + case tnet_stun_attr_type_alternate_server: + case tnet_stun_attr_type_xor_mapped_address: + case tnet_stun_attr_type_xor_peer_address: + case tnet_stun_attr_type_xor_relayed_address: { + extern const tsk_object_def_t *tnet_stun_attr_address_def_t; + const tnet_stun_attr_address_t* _pc_self = (const tnet_stun_attr_address_t*)pc_self; + if (pc_self->__def__ != tnet_stun_attr_address_def_t) { + TSK_DEBUG_ERROR("Invalid base type"); + return -2; + } + *p_size = (kStunAttrHdrSizeInOctets + 1/*Ignored*/ + 1/*Family*/ + 2/*Port*/ + ((_pc_self->e_family == tnet_stun_address_family_ipv6) ? 16 : 4)); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + case tnet_stun_attr_type_data: + case tnet_stun_attr_type_unknown_attrs: + case tnet_stun_attr_type_dont_fragment: + case tnet_stun_attr_type_software: + case tnet_stun_attr_type_nonce: + case tnet_stun_attr_type_realm: + case tnet_stun_attr_type_username: + case tnet_stun_attr_type_password: + case tnet_stun_attr_type_channel_number: + case tnet_stun_attr_type_message_integrity: + case tnet_stun_attr_type_fingerprint: + case tnet_stun_attr_type_lifetime: + case tnet_stun_attr_type_requested_transport: + case tnet_stun_attr_type_ice_use_candidate: + case tnet_stun_attr_type_ice_priority: + case tnet_stun_attr_type_ice_controlled: + case tnet_stun_attr_type_ice_controlling: + case tnet_stun_attr_type_connection_id: { + extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t; + const tnet_stun_attr_vdata_t* _pc_self = (const tnet_stun_attr_vdata_t*)pc_self; + if (pc_self->__def__ != tnet_stun_attr_vdata_def_t) { + TSK_DEBUG_ERROR("Invalid base type"); + return -2; + } + *p_size = (kStunAttrHdrSizeInOctets + _pc_self->u_data_size); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + case tnet_stun_attr_type_error_code: { + const tnet_stun_attr_error_code_t* _pc_self = (const tnet_stun_attr_error_code_t*)pc_self; + *p_size = (kStunAttrHdrSizeInOctets + 4 + (tsk_size_t)tsk_strlen(_pc_self->p_reason_phrase)); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + default: { + TSK_DEBUG_WARN("Attribute type=%d is unknown. Don't be surprised if something goes wrong.", pc_self->hdr.e_type); + *p_size = (kStunAttrHdrSizeInOctets + pc_self->hdr.u_length); + if (with_padding) { + ALIGN_ON_32BITS(*p_size); + } + return 0; + } + } +} + +static int _tnet_stun_attr_write(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t with_padding, tsk_size_t *p_written) +{ + tsk_size_t n_min_req_size; + int ret; + if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = _tnet_stun_attr_get_size_in_octetunits(pc_self, with_padding, &n_min_req_size))) { + return ret; + } + if (n_min_req_size > n_buff_size) { + TSK_DEBUG_ERROR("Buffer too short %u<%u", (unsigned)n_buff_size, (unsigned)n_min_req_size); + return -2; + } + + *((uint16_t*)&p_buff_ptr[0]) = tnet_htons((unsigned short)pc_self->hdr.e_type); + // *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)pc_self->hdr.u_length); + *p_written = kStunAttrHdrSizeInOctets; + + switch (pc_self->hdr.e_type) { + case tnet_stun_attr_type_mapped_address: + case tnet_stun_attr_type_alternate_server: + case tnet_stun_attr_type_xor_mapped_address: + case tnet_stun_attr_type_xor_peer_address: + case tnet_stun_attr_type_xor_relayed_address: { + tsk_size_t u_addr_size; + extern const tsk_object_def_t *tnet_stun_attr_address_def_t; + const tnet_stun_attr_address_t* _pc_self = (const tnet_stun_attr_address_t*)pc_self; + tsk_bool_t b_xor = IS_ADDRESS_XOR(pc_self->hdr.e_type); + if (pc_self->__def__ != tnet_stun_attr_address_def_t) { + TSK_DEBUG_ERROR("Invalid base type"); + return -2; + } + p_buff_ptr[*p_written] = 0x00; // Reserved + p_buff_ptr[*p_written + 1] = _pc_self->e_family; + u_addr_size = (_pc_self->e_family == tnet_stun_address_family_ipv6 ? 16 : 4); + if (b_xor) { + tsk_size_t u; + *((uint16_t*)&p_buff_ptr[*p_written + 2]) = tnet_htons(_pc_self->u_port ^ kStunMagicCookieShort); + *((uint32_t*)&p_buff_ptr[*p_written + 4]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[0])) ^ kStunMagicCookieLong); + for (u = 4; u < u_addr_size; u += 4) { + if (pc_transac_id) { + *((uint32_t*)&p_buff_ptr[*p_written + 4 + u]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[u])) ^ tnet_ntohl(*((uint32_t*)(*pc_transac_id + u - 4)))); + } + else { + *((uint32_t*)&p_buff_ptr[*p_written + 4 + u]) = (uint32_t)tnet_htonl(tnet_ntohl(*((uint32_t*)&_pc_self->address[u])) ^ 0); + } + } + } + else { + *((uint16_t*)&p_buff_ptr[*p_written + 2]) = tnet_htons(_pc_self->u_port); + memcpy(&p_buff_ptr[*p_written + 4], _pc_self->address, u_addr_size); + } + + *p_written += 4 + u_addr_size; + *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets); + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + return 0; + } + + case tnet_stun_attr_type_data: + case tnet_stun_attr_type_unknown_attrs: + case tnet_stun_attr_type_dont_fragment: + case tnet_stun_attr_type_software: + case tnet_stun_attr_type_nonce: + case tnet_stun_attr_type_realm: + case tnet_stun_attr_type_username: + case tnet_stun_attr_type_password: + case tnet_stun_attr_type_channel_number: + case tnet_stun_attr_type_message_integrity: + case tnet_stun_attr_type_fingerprint: + case tnet_stun_attr_type_lifetime: + case tnet_stun_attr_type_requested_transport: + case tnet_stun_attr_type_ice_use_candidate: + case tnet_stun_attr_type_ice_priority: + case tnet_stun_attr_type_ice_controlled: + case tnet_stun_attr_type_ice_controlling: + case tnet_stun_attr_type_connection_id: { + extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t; + const tnet_stun_attr_vdata_t* _pc_self = (const tnet_stun_attr_vdata_t*)pc_self; + if (pc_self->__def__ != tnet_stun_attr_vdata_def_t) { + TSK_DEBUG_ERROR("Invalid base type"); + return -2; + } + if (_pc_self->p_data_ptr && _pc_self->u_data_size) { + if (IS_VDATA_UINT16(pc_self->hdr.e_type) && _pc_self->u_data_size == 2) { + *((uint16_t*)&p_buff_ptr[*p_written]) = tnet_htons_2(&_pc_self->p_data_ptr[0]); + } + else if (IS_VDATA_UINT32(pc_self->hdr.e_type) && _pc_self->u_data_size == 4) { + *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[0]); + } + else if (IS_VDATA_UINT64(pc_self->hdr.e_type) && _pc_self->u_data_size == 8) { + *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[0]); + *((uint32_t*)&p_buff_ptr[*p_written + 4]) = (uint32_t)tnet_htonl_2(&_pc_self->p_data_ptr[4]); + } + else if (pc_self->hdr.e_type == tnet_stun_attr_type_unknown_attrs && _pc_self->u_data_size && !(_pc_self->u_data_size & 1)) { + uint16_t u; + for (u = 0; u < _pc_self->u_data_size; u += 2) { + *((uint16_t*)&p_buff_ptr[*p_written + u]) = tnet_htons_2(&_pc_self->p_data_ptr[u]); + } + } + else { + memcpy(&p_buff_ptr[*p_written], _pc_self->p_data_ptr, _pc_self->u_data_size); + } + *p_written += _pc_self->u_data_size; + } + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets); + return 0; + } + case tnet_stun_attr_type_error_code: { + const tnet_stun_attr_error_code_t* _pc_self = (const tnet_stun_attr_error_code_t*)pc_self; + *((uint32_t*)&p_buff_ptr[*p_written]) = (uint32_t)tnet_htonl(((_pc_self->u_class & 0x07) << 8) | _pc_self->u_number); + if (_pc_self->p_reason_phrase) { + memcpy(&p_buff_ptr[*p_written + 4], _pc_self->p_reason_phrase, tsk_strlen(_pc_self->p_reason_phrase)); + } + *p_written += 4 + tsk_strlen(_pc_self->p_reason_phrase); + if (with_padding) { + ALIGN_ON_32BITS_AND_SET_PADDING_ZEROS(&p_buff_ptr[*p_written], *p_written); + } + *((uint16_t*)&p_buff_ptr[2]) = tnet_htons((unsigned short)*p_written - kStunAttrHdrSizeInOctets); + return 0; + } + default: { + TSK_DEBUG_ERROR("Attribute type=%d is unknown.", pc_self->hdr.e_type); + return -2; + } + } +} + +int tnet_stun_attr_init(tnet_stun_attr_t* p_self, tnet_stun_attr_type_t e_type, uint16_t u_length) +{ + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + p_self->hdr.e_type = e_type; + p_self->hdr.u_length = u_length; + return 0; +} + +int tnet_stun_attr_get_size_in_octetunits_without_padding(const tnet_stun_attr_t* pc_self, tsk_size_t* p_size) +{ + return _tnet_stun_attr_get_size_in_octetunits(pc_self, kWithoutPadding, p_size); +} + +int tnet_stun_attr_get_size_in_octetunits_with_padding(const tnet_stun_attr_t* pc_self, tsk_size_t* p_size) +{ + return _tnet_stun_attr_get_size_in_octetunits(pc_self, kWithPadding, p_size); +} + +int tnet_stun_attr_write_without_padding(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + return _tnet_stun_attr_write(pc_transac_id, pc_self, p_buff_ptr, n_buff_size, kWithoutPadding, p_written); +} + +int tnet_stun_attr_write_with_padding(const tnet_stun_transac_id_t* pc_transac_id, const tnet_stun_attr_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + return _tnet_stun_attr_write(pc_transac_id, pc_self, p_buff_ptr, n_buff_size, kWithPadding, p_written); +} + +int tnet_stun_attr_read(const tnet_stun_transac_id_t* pc_transac_id, const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, tnet_stun_attr_t** pp_attr) +{ + tnet_stun_attr_type_t Type; + uint16_t Length, PadLength; + int ret = -1; + static const void* kNullBuffPtr = tsk_null; + if (!pc_buff_ptr || !n_buff_size || !pp_attr || !p_consumed_octets) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (n_buff_size < kStunAttrHdrSizeInOctets) { + TSK_DEBUG_ERROR("Buffer too short(%u)", (unsigned)n_buff_size); + return -2; + } + + Type = tnet_ntohs_2(&pc_buff_ptr[0]); + Length = tnet_ntohs_2(&pc_buff_ptr[2]); + if (Length > n_buff_size) { + TSK_DEBUG_ERROR("Buffer too short(%u). Length=%u", (unsigned)n_buff_size, (unsigned)Length); + return -3; + } + + PadLength = (Length & 0x03) ? (4 - (Length & 0x03)) : 0; + + *pp_attr = tsk_null; + *p_consumed_octets = kStunAttrHdrSizeInOctets + Length + PadLength; + + switch (Type) { + case tnet_stun_attr_type_mapped_address: + case tnet_stun_attr_type_alternate_server: + case tnet_stun_attr_type_xor_mapped_address: + case tnet_stun_attr_type_xor_peer_address: + case tnet_stun_attr_type_xor_relayed_address: { + // First 8bits must be ignored + tnet_stun_address_family_t e_family = pc_buff_ptr[5]; + uint16_t u_port = tnet_ntohs_2(&pc_buff_ptr[6]); + tnet_stun_attr_address_t* p_attr; + tsk_bool_t b_xor = IS_ADDRESS_XOR(Type); + uint16_t u, u_addr_size = (e_family == tnet_stun_address_family_ipv6) ? 16 : 4; + + if (b_xor) { + u_port ^= kStunMagicCookieShort; + } + if ((ret = tnet_stun_attr_address_create(Type, e_family, u_port, (const tnet_stun_addr_t*)kNullBuffPtr, &p_attr))) { + return ret; + } + if (b_xor) { + *((uint32_t*)&p_attr->address[0]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8]) ^ kStunMagicCookieLong); + for (u = 4; u < u_addr_size; u += 4) { + if (pc_transac_id) { + *((uint32_t*)&p_attr->address[u]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8 + u]) ^ tnet_ntohl_2(((uint32_t*)(*pc_transac_id + u - 4)))); + } + else { + *((uint32_t*)&p_attr->address[u]) = (uint32_t)tnet_htonl(tnet_ntohl_2(&pc_buff_ptr[8 + u]) ^ 0); + } + } + } + else { + memcpy(p_attr->address, &pc_buff_ptr[8], u_addr_size); + } + *pp_attr = TNET_STUN_ATTR(p_attr); + break; + } + + case tnet_stun_attr_type_error_code: { + // First 21bits must be ignored + uint8_t Class = pc_buff_ptr[6] & 0x07; + uint8_t Number = pc_buff_ptr[7] & 0xff; + tnet_stun_attr_error_code_t* p_attr; + if ((ret = tnet_stun_attr_error_code_create(Class, Number, &pc_buff_ptr[8], (Length - 4), &p_attr))) { + return ret; + } + *pp_attr = TNET_STUN_ATTR(p_attr); + break; + } + + case tnet_stun_attr_type_data: + case tnet_stun_attr_type_unknown_attrs: + case tnet_stun_attr_type_dont_fragment: + case tnet_stun_attr_type_software: + case tnet_stun_attr_type_nonce: + case tnet_stun_attr_type_realm: + case tnet_stun_attr_type_username: + case tnet_stun_attr_type_password: + case tnet_stun_attr_type_channel_number: + case tnet_stun_attr_type_message_integrity: + case tnet_stun_attr_type_fingerprint: + case tnet_stun_attr_type_lifetime: + case tnet_stun_attr_type_requested_transport: + case tnet_stun_attr_type_ice_use_candidate: + case tnet_stun_attr_type_ice_priority: + case tnet_stun_attr_type_ice_controlled: + case tnet_stun_attr_type_ice_controlling: + case tnet_stun_attr_type_connection_id: + default: { + tnet_stun_attr_vdata_t* p_attr; + if (IS_VDATA_UINT16(Type) && Length == 2) { + uint16_t u16 = tnet_ntohs_2(&pc_buff_ptr[4]); + if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u16, 2, &p_attr))) { + return ret; + } + } + else if (IS_VDATA_UINT32(Type) && Length == 4) { + uint32_t u32 = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]); + if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u32, 4, &p_attr))) { + return ret; + } + } + else if (IS_VDATA_UINT64(Type) && Length == 8) { + uint64_t u64 = ((uint64_t)tnet_ntohl_2(&pc_buff_ptr[4])) << 32; + u64 |= tnet_ntohl_2(&pc_buff_ptr[8]); + if ((ret = tnet_stun_attr_vdata_create(Type, (uint8_t*)&u64, 8, &p_attr))) { + return ret; + } + } + else if (Type == tnet_stun_attr_type_unknown_attrs && Length && !(Length & 1)) { + uint16_t u; + uint8_t *_p_data_ptr = tsk_malloc(Length); + if (!_p_data_ptr) { + TSK_DEBUG_ERROR("Failed to allocate buffer with size = %u", Length); + return -4; + } + memcpy(_p_data_ptr, &pc_buff_ptr[4], Length); + for (u = 0; u < Length; u += 2) { + *((uint16_t*)&_p_data_ptr[u]) = tnet_htons_2(&_p_data_ptr[u]); + } + if ((ret = tnet_stun_attr_vdata_create(Type, _p_data_ptr, Length, &p_attr))) { + TSK_FREE(_p_data_ptr); + return ret; + } + TSK_FREE(_p_data_ptr); + } + else { + if ((ret = tnet_stun_attr_vdata_create(Type, &pc_buff_ptr[4], Length, &p_attr))) { + return ret; + } + } + *pp_attr = TNET_STUN_ATTR(p_attr); + break; + } + } + return ret; +} + +// ============== VDATA (USERNAME, MESSAGE-INTEGRITY, ...) ================ // +int tnet_stun_attr_vdata_create(tnet_stun_attr_type_t e_type, const uint8_t* pc_data_ptr, uint16_t u_data_size, tnet_stun_attr_vdata_t** pp_attr) +{ + int ret = -1; + uint16_t u_length = pc_data_ptr ? u_data_size : 0; + tnet_stun_attr_vdata_t* p_attr = tsk_null; + extern const tsk_object_def_t *tnet_stun_attr_vdata_def_t; + if (!pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if (!(p_attr = tsk_object_new(tnet_stun_attr_vdata_def_t))) { + ret = -2; + goto bail; + } + if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), e_type, u_length))) { + goto bail; + } + if (u_length) { + if (!(p_attr->p_data_ptr = tsk_malloc(u_length + 1))) { + ret = -3; + goto bail; + } + memcpy(p_attr->p_data_ptr, pc_data_ptr, u_length); + p_attr->u_data_size = u_length; + p_attr->p_data_ptr[u_length] = '\0'; + } + *pp_attr = p_attr; + +bail: + if (ret) { + TSK_OBJECT_SAFE_FREE(p_attr); + } + return ret; +} + +int tnet_stun_attr_vdata_update(tnet_stun_attr_vdata_t* p_self, const uint8_t* pc_data_ptr, uint16_t u_data_size) +{ + uint16_t _u_data_size = (pc_data_ptr && u_data_size) ? u_data_size : 0; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (_u_data_size) { + if (!(p_self->p_data_ptr = tsk_realloc(p_self->p_data_ptr, _u_data_size + 1))) { + p_self->u_data_size = 0; + ((tnet_stun_attr_t*)p_self)->hdr.u_length = 0; + return -3; + } + memcpy(p_self->p_data_ptr, pc_data_ptr, _u_data_size); + p_self->p_data_ptr[_u_data_size] = '\0'; + } + else { + TSK_FREE(p_self->p_data_ptr); + } + p_self->u_data_size = _u_data_size; + ((tnet_stun_attr_t*)p_self)->hdr.u_length = p_self->u_data_size; + return 0; +} + +static tsk_object_t* tnet_stun_attr_vdata_ctor(tsk_object_t * self, va_list * app) +{ + tnet_stun_attr_vdata_t *p_vdata = (tnet_stun_attr_vdata_t *)self; + if (p_vdata) { + } + return self; +} +static tsk_object_t* tnet_stun_attr_vdata_dtor(tsk_object_t * self) +{ + tnet_stun_attr_vdata_t *p_vdata = (tnet_stun_attr_vdata_t *)self; + if (p_vdata) { +#if PRINT_DESTROYED_MSG + TSK_DEBUG_INFO("*** STUN Attribute(VDATA) destroyed ***"); +#endif + TSK_FREE(p_vdata->p_data_ptr); + } + return self; +} +static const tsk_object_def_t tnet_stun_attr_vdata_def_s = { + sizeof(tnet_stun_attr_vdata_t), + tnet_stun_attr_vdata_ctor, + tnet_stun_attr_vdata_dtor, + _tnet_stun_attr_cmp, +}; +const tsk_object_def_t *tnet_stun_attr_vdata_def_t = &tnet_stun_attr_vdata_def_s; + + +// ============== ADDRESS ================ // +int tnet_stun_attr_address_create(tnet_stun_attr_type_t e_type, tnet_stun_address_family_t e_family, uint16_t u_port, const tnet_stun_addr_t* pc_addr, tnet_stun_attr_address_t** pp_attr) +{ + int ret = -1; + extern const tsk_object_def_t *tnet_stun_attr_address_def_t; + tnet_stun_attr_address_t* p_attr = tsk_null; + uint16_t u_length = (e_family == tnet_stun_address_family_ipv6) ? 16 : 4; + if (!pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_attr = tsk_object_new(tnet_stun_attr_address_def_t))) { + ret = -2; + goto bail; + } + if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), e_type, u_length))) { + goto bail; + } + p_attr->e_family = e_family; + p_attr->u_port = u_port; + if (pc_addr) { + memcpy(p_attr->address, *pc_addr, u_length); + } + *pp_attr = p_attr; + +bail: + if (ret) { + TSK_OBJECT_SAFE_FREE(p_attr); + } + return ret; +} + +static tsk_object_t* tnet_stun_attr_address_ctor(tsk_object_t * self, va_list * app) +{ + tnet_stun_attr_address_t *p_addr = (tnet_stun_attr_address_t *)self; + if (p_addr) { + } + return self; +} +static tsk_object_t* tnet_stun_attr_address_dtor(tsk_object_t * self) +{ + tnet_stun_attr_address_t *p_addr = (tnet_stun_attr_address_t *)self; + if (p_addr) { +#if PRINT_DESTROYED_MSG + TSK_DEBUG_INFO("*** STUN Attribute(ADDRESS) destroyed ***"); +#endif + } + return self; +} +static const tsk_object_def_t tnet_stun_attr_address_def_s = { + sizeof(tnet_stun_attr_address_t), + tnet_stun_attr_address_ctor, + tnet_stun_attr_address_dtor, + _tnet_stun_attr_cmp, +}; +const tsk_object_def_t *tnet_stun_attr_address_def_t = &tnet_stun_attr_address_def_s; + + + +// ================ 15.6. ERROR-CODE ========== // +int tnet_stun_attr_error_code_create(uint8_t u_class, uint8_t u_number, const void* pc_reason_phrase, uint16_t u_reason_phrase, struct tnet_stun_attr_error_code_s** pp_attr) +{ + int ret = -1; + extern const tsk_object_def_t *tnet_stun_attr_error_code_def_t; + tnet_stun_attr_error_code_t* p_attr = tsk_null; + uint16_t u_length = (uint16_t)(4 + tsk_strlen(pc_reason_phrase)); + if (!pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(p_attr = tsk_object_new(tnet_stun_attr_error_code_def_t))) { + ret = -2; + goto bail; + } + if ((ret = tnet_stun_attr_init(TNET_STUN_ATTR(p_attr), tnet_stun_attr_type_error_code, u_length))) { + goto bail; + } + p_attr->u_class = u_class; + p_attr->u_number = u_number; + if (pc_reason_phrase && u_reason_phrase) { + if (!(p_attr->p_reason_phrase = tsk_strndup(pc_reason_phrase, u_reason_phrase))) { + ret = -3; + goto bail; + } + } + *pp_attr = p_attr; + +bail: + if (ret) { + TSK_OBJECT_SAFE_FREE(p_attr); + } + return ret; +} + +static tsk_object_t* tnet_stun_attr_error_code_ctor(tsk_object_t * self, va_list * app) +{ + tnet_stun_attr_error_code_t *p_ec = (tnet_stun_attr_error_code_t *)self; + if (p_ec) { + } + return self; +} +static tsk_object_t* tnet_stun_attr_error_code_dtor(tsk_object_t * self) +{ + tnet_stun_attr_error_code_t *p_ec = (tnet_stun_attr_error_code_t *)self; + if (p_ec) { +#if PRINT_DESTROYED_MSG + TSK_DEBUG_INFO("*** STUN Attribute(ERROR-CODE) destroyed ***"); +#endif + TSK_FREE(p_ec->p_reason_phrase); + } + return self; +} +static const tsk_object_def_t tnet_stun_attr_error_code_def_s = { + sizeof(tnet_stun_attr_error_code_t), + tnet_stun_attr_error_code_ctor, + tnet_stun_attr_error_code_dtor, + _tnet_stun_attr_cmp, +}; +const tsk_object_def_t *tnet_stun_attr_error_code_def_t = &tnet_stun_attr_error_code_def_s; diff --git a/tinyNET/src/stun/tnet_stun_attr.h b/tinyNET/src/stun/tnet_stun_attr.h new file mode 100644 index 0000000..0052c66 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_attr.h @@ -0,0 +1,81 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TNET_STUN_ATTR_H +#define TNET_STUN_ATTR_H + +#include "tinynet_config.h" +#include "stun/tnet_stun_types.h" + +#include "tsk_object.h" +#include "tsk_list.h" + +TNET_BEGIN_DECLS + +// rfc5389 - 15. STUN Attributes +typedef struct tnet_stun_attr_hdr_xs { + enum tnet_stun_attr_type_e e_type; // 16bits + uint16_t u_length; // 16bits prior to padding, measured in bytes (WITHOUT header) +} tnet_stun_attr_hdr_xt; + +typedef struct tnet_stun_attr_s { + TSK_DECLARE_OBJECT; + struct tnet_stun_attr_s* pc_base; + struct tnet_stun_attr_hdr_xs hdr; +} tnet_stun_attr_t; +#define TNET_STUN_DECLARE_ATTR struct tnet_stun_attr_s __base__ +#define TNET_STUN_ATTR(p_self) ((struct tnet_stun_attr_s*)(p_self)) +typedef tsk_list_t tnet_stun_attrs_L_t; +int tnet_stun_attr_init(struct tnet_stun_attr_s* p_self, enum tnet_stun_attr_type_e e_type, uint16_t u_length); +TINYNET_API int tnet_stun_attr_get_size_in_octetunits_without_padding(const struct tnet_stun_attr_s* pc_self, tsk_size_t* p_size); +TINYNET_API int tnet_stun_attr_get_size_in_octetunits_with_padding(const struct tnet_stun_attr_s* pc_self, tsk_size_t* p_size); +TINYNET_API int tnet_stun_attr_write_without_padding(const tnet_stun_transac_id_t* pc_transac_id, const struct tnet_stun_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYNET_API int tnet_stun_attr_write_with_padding(const tnet_stun_transac_id_t* pc_transac_id, const struct tnet_stun_attr_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYNET_API int tnet_stun_attr_read(const tnet_stun_transac_id_t* pc_transac_id, const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_consumed_octets, struct tnet_stun_attr_s** pp_attr); + +// ============== VDATA (USERNAME, MESSAGE-INTEGRITY, REALM, NONCE, ...) ================ // +typedef struct tnet_stun_attr_vdata_s { + TNET_STUN_DECLARE_ATTR; + uint8_t *p_data_ptr; + uint16_t u_data_size; +} tnet_stun_attr_vdata_t; +int tnet_stun_attr_vdata_create(enum tnet_stun_attr_type_e e_type, const uint8_t* pc_data_ptr, uint16_t u_data_size, struct tnet_stun_attr_vdata_s** pp_attr); +int tnet_stun_attr_vdata_update(struct tnet_stun_attr_vdata_s* p_self, const uint8_t* pc_data_ptr, uint16_t u_data_size); + +// ============== ADDRESS ================ // +typedef struct tnet_stun_attr_address_s { + TNET_STUN_DECLARE_ATTR; + enum tnet_stun_address_family_e e_family; // 8bits + uint16_t u_port; // 16bits + tnet_stun_addr_t address; // always in network byte order. Use tnet_stun_utils_inet_pton() +} tnet_stun_attr_address_t; + +int tnet_stun_attr_address_create(enum tnet_stun_attr_type_e e_type, enum tnet_stun_address_family_e e_family, uint16_t u_port, const tnet_stun_addr_t* pc_addr, struct tnet_stun_attr_address_s** pp_attr); + +// ================ 15.6. ERROR-CODE ========== // +typedef struct tnet_stun_attr_error_code_s { + TNET_STUN_DECLARE_ATTR; + uint8_t u_class; // 3bits + uint8_t u_number; // 8bits + char* p_reason_phrase; +} tnet_stun_attr_error_code_t; +int tnet_stun_attr_error_code_create(uint8_t u_class, uint8_t u_number, const void* pc_reason_phrase, uint16_t u_reason_phrase, struct tnet_stun_attr_error_code_s** pp_attr); + +TNET_END_DECLS + +#endif /* TNET_STUN_ATTR_H */ diff --git a/tinyNET/src/stun/tnet_stun_attribute.c b/tinyNET/src/stun/tnet_stun_attribute.c new file mode 100644 index 0000000..b8efdcc --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_attribute.c @@ -0,0 +1,1176 @@ +///* +//* 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_attribute.c +// * @brief STUN2(RFC 5389) attribute parser. +// * +// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> +// * +// +// */ +//#include "tnet_stun_attribute.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_string.h" +//#include "tsk_debug.h" +// +//#include <string.h> +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15. STUN Attributes +//* Creates new @ref tnet_stun_attribute_def_t object. +//*/ +//tnet_stun_attr_t* tnet_stun_attribute_create() +//{ +// return tsk_object_new(tnet_stun_attribute_def_t); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.1. MAPPED-ADDRESS. +//* Creates new @ref tnet_stun_attribute_mapped_addr_t object. +//*/ +//tnet_stun_attribute_mapped_addr_t* tnet_stun_attribute_mapped_address_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_mapped_addr_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS. +//* Creates new @ref tnet_stun_attribute_xmapped_addr_t object. +//*/ +//tnet_stun_attribute_xmapped_addr_t* tnet_stun_attribute_xmapped_address_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_xmapped_addr_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.3. USERNAME. +//* Creates new @ref tnet_stun_attribute_username_t object. +//*/ +//tnet_stun_attribute_username_t* tnet_stun_attribute_username_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_username_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.4. MESSAGE-INTEGRITY. +//* Creates new @ref tnet_stun_attribute_integrity_t object. +//*/ +//tnet_stun_attribute_integrity_t* tnet_stun_attribute_integrity_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_integrity_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.5. FINGERPRINT. +//* Creates new @ref tnet_stun_attribute_fingerprint_t object. +//*/ +//tnet_stun_attribute_fingerprint_t* tnet_stun_attribute_fingerprint_create(uint32_t fingerprint) +//{ +// return tsk_object_new(tnet_stun_attribute_fingerprint_def_t, fingerprint); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.6. ERROR-CODE +//* Creates new @ref tnet_stun_attribute_errorcode_t object. +//*/ +//tnet_stun_attribute_errorcode_t* tnet_stun_attribute_errorcode_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_errorcode_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.7. REALM. +//* Creates new @ref tnet_stun_attribute_realm_t object. +//*/ +//tnet_stun_attribute_realm_t* tnet_stun_attribute_realm_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_realm_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.8. NONCE. +//* Creates new @ref tnet_stun_attribute_nonce_t object. +//*/ +//tnet_stun_attribute_nonce_t* tnet_stun_attribute_nonce_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_nonce_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES. +//* Creates new @ref tnet_stun_attribute_unknowns_t object. +//*/ +//tnet_stun_attribute_unknowns_t* tnet_stun_attribute_unknowns_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_unknowns_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.10. SOFTWARE. +//* Creates new @ref tnet_stun_attribute_software_t object. +//*/ +//tnet_stun_attribute_software_t* tnet_stun_attribute_software_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_software_def_t, payload, payload_size); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.11. ALTERNATE-SERVER. +//* Creates new @ref tnet_stun_attribute_altserver_t object. +//*/ +//tnet_stun_attribute_altserver_t* tnet_stun_attribute_altserver_create(const void* payload, tsk_size_t payload_size) +//{ +// return tsk_object_new(tnet_stun_attribute_altserver_def_t, payload, payload_size); +//} +// +// +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. PRIORITY */ +//tnet_stun_attribute_ice_priority_t* tnet_stun_attribute_ice_priority_create(uint32_t value) +//{ +// return tsk_object_new(tnet_stun_attribute_ice_priority_def_t, value); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. USE_CANDIDATE */ +//tnet_stun_attribute_ice_use_candidate_t* tnet_stun_attribute_ice_use_candidate_create() +//{ +// return tsk_object_new(tnet_stun_attribute_ice_use_candidate_def_t); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. ICE_CONTROLLED */ +//tnet_stun_attribute_ice_controlled_t* tnet_stun_attribute_ice_controlled_create(uint64_t value) +//{ +// return tsk_object_new(tnet_stun_attribute_ice_controlled_def_t, value); +//} +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. ICE_CONTROLLING */ +//tnet_stun_attribute_ice_controlling_t* tnet_stun_attribute_ice_controlling_create(uint64_t value) +//{ +// return tsk_object_new(tnet_stun_attribute_ice_controlling_def_t, value); +//} +// +// +// +// +///**@ingroup tnet_stun_group +//* Creates @ref tnet_stun_attr_t from raw buffer. +//* @param data Raw buffer from which to create the STUN attribute.* +//* @param size The size of the eaw buffer. +//* @retval @ref tnet_stun_attr_t object if succeed and NULL other wise. +//*/ +//tnet_stun_attr_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size) +//{ +// tnet_stun_attr_t *attribute = 0; +// const uint8_t* dataPtr = data; +// +// tnet_stun_attr_type_t type = (tnet_stun_attr_type_t)tnet_ntohs_2(dataPtr); +// uint16_t length = tnet_ntohs_2(&dataPtr[2]); +// +// /* Check validity */ +// if(!data || size<=4/* Type(2-bytes) plus Length (2-bytes) */) { +// return 0; +// } +// +// dataPtr += (2 /* Type */+ 2/* Length */); +// +// /* Attribute Value +// */ +// +// switch(type) { +// /* RFC 5389 - 15.1. MAPPED-ADDRESS */ +// case stun_mapped_address: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_mapped_address_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS*/ +// case stun_xor_mapped_address: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_xmapped_address_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.3. USERNAME*/ +// case stun_username: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_username_create(dataPtr, length); +// break; +// } +// +// +// /* RFC 5389 - MESSAGE-INTEGRITY*/ +// case stun_message_integrity: { +// if(length == TSK_SHA1_DIGEST_SIZE) { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_integrity_create(dataPtr, length); +// } +// break; +// } +// +// /* RFC 5389 - 15.5. FINGERPRINT*/ +// case stun_fingerprint: { +// uint32_t fingerprint = tnet_htonl_2(dataPtr); +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_fingerprint_create(fingerprint); +// break; +// } +// +// /* RFC 5389 - 15.6. ERROR-CODE*/ +// case stun_error_code: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_errorcode_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.7. REALM*/ +// case stun_realm: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_realm_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.8. NONCE*/ +// case stun_nonce: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_nonce_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES*/ +// case stun_unknown_attributes: { +// TSK_DEBUG_ERROR("DESERIALIZE:UNKNOWN-ATTRIBUTES ==> NOT IMPLEMENTED"); +// attribute = tnet_stun_attribute_create(); +// break; +// } +// +// /* RFC 5389 - 15.10. SOFTWARE */ +// case stun_software: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_software_create(dataPtr, length); +// break; +// } +// +// /* RFC 5389 - 15.11. ALTERNATE-SERVER */ +// case stun_alternate_server: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_altserver_create(dataPtr, length); +// break; +// } +// +// /* draft-ietf-behave-turn-16 subclause 14 */ +// case stun_channel_number: +// case stun_lifetime: +// case stun_reserved2: +// case stun_xor_peer_address: +// case stun_data: +// case stun_xor_relayed_address: +// case stun_even_port: +// case stun_requested_transport: +// case stun_dont_fragment: +// case stun_reserved3: +// case stun_reservation_token: { +// //attribute = tnet_turn_attribute_deserialize(type, length, dataPtr, length); +// attribute = 0; +// break; +// } +// +// /* RFC 5245 - 19.1. PRIORITY */ +// case stun_ice_priority: { +// if(length >= 4) { +// uint32_t value = dataPtr[0] << 24 | dataPtr[1] << 16 | dataPtr[2] << 8 | dataPtr[3]; +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_priority_create(value); +// } +// break; +// } +// /* RFC 5245 - 19.1. USE_CANDIDATE */ +// case stun_ice_use_candidate: { +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_use_candidate_create(); +// break; +// } +// /* RFC 5245 - 19.1. ICE_CONTROLLED*/ +// case stun_ice_controlled: { +// if(length >= 8) { +// uint64_t value = ((((uint64_t)dataPtr[0]) << 56) | (((uint64_t)dataPtr[1]) << 48) | (((uint64_t)dataPtr[2]) << 40) | (((uint64_t)dataPtr[3]) << 32) | (((uint64_t)dataPtr[4]) << 24) | (((uint64_t)dataPtr[5]) << 16) | ((uint64_t)dataPtr[6]) << 8 | ((uint64_t)dataPtr[7])); +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_controlled_create(value); +// } +// break; +// } +// /* RFC 5245 - 19.1. ICE_CONTROLLING*/ +// case stun_ice_controlling: { +// if(length >= 8) { +// uint64_t value = ((((uint64_t)dataPtr[0]) << 56) | (((uint64_t)dataPtr[1]) << 48) | (((uint64_t)dataPtr[2]) << 40) | (((uint64_t)dataPtr[3]) << 32) | (((uint64_t)dataPtr[4]) << 24) | (((uint64_t)dataPtr[5]) << 16) | ((uint64_t)dataPtr[6]) << 8 | ((uint64_t)dataPtr[7])); +// attribute = (tnet_stun_attr_t *)tnet_stun_attribute_ice_controlling_create(value); +// } +// break; +// } +// +// +// default: +// //TSK_DEBUG_WARN("==> NOT IMPLEMENTED"); +// break; +// } +// +// if(!attribute) { +// /* Create default */ +// attribute = tnet_stun_attribute_create(); +// } +// +// /* Set common values (Do I need this ==> already set by the constructor). */ +// attribute->type = type; +// attribute->length = length; +// +// return attribute; +//} +// +///**@ingroup tnet_stun_group +//* Serializes a @ref tnet_stun_attr_t objet in binary format. +//* @param attribute The STUN attribute to serialize. +//* @param output The output binary buffer. +//* @retval Zero if succeed and non-zero error code otherwise. +//*/ +//int tnet_stun_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output) +//{ +// if(!attribute || !output) { +// return -1; +// } +// +// /* Attribute Type +// */ +// { +// uint16_t type = tnet_htons(attribute->type); +// tsk_buffer_append(output, &(type), 2); +// } +// +// /* Attribute Length +// */ +// { +// uint16_t length = tnet_htons(attribute->length); +// tsk_buffer_append(output, &(length), 2); +// } +// +// /* Attribute Value */ +// // NEED to be refactorized +// +// switch(attribute->type) { +// /* RFC 5389 - 15.1. MAPPED-ADDRESS */ +// case stun_mapped_address: { +// uint32_t u32 = 0; +// tnet_stun_attribute_mapped_addr_t* ma = (tnet_stun_attribute_mapped_addr_t*)attribute; +// tsk_size_t addr_size, i; +// uint32_t addr[4]; +// +// u32 |= (ma->family << 16); +// u32 |= (ma->port); +// u32 = tnet_htonl(u32); +// tsk_buffer_append(output, &u32, 4); +// +// addr_size = (ma->family == stun_ipv6 ? 16 : 4); +// for(i = 0; i < addr_size; i += 4) { +// addr[i >> 2] = tnet_htonl_2(&ma->address[i]); +// } +// tsk_buffer_append(output, addr, addr_size); +// +// return 0; +// } +// +// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS*/ +// case stun_xor_mapped_address: { +// uint32_t u32 = 0; +// tnet_stun_attribute_xmapped_addr_t* xma = (tnet_stun_attribute_xmapped_addr_t*)attribute; +// tsk_size_t addr_size, i; +// uint32_t addr[4]; +// +// u32 |= (xma->family << 16); +// u32 |= (xma->xport); +// u32 = tnet_htonl(u32); +// tsk_buffer_append(output, &u32, 4); +// +// addr_size = (xma->family == stun_ipv6 ? 16 : 4); +// for(i = 0; i < addr_size; i += 4) { +// addr[i >> 2] = tnet_htonl_2(&xma->xaddress[i]); +// } +// tsk_buffer_append(output, addr, addr_size); +// return 0; +// } +// +// /* RFC 5389 - 15.3. USERNAME*/ +// case stun_username: { +// tnet_stun_attribute_username_t *username = (tnet_stun_attribute_username_t*)attribute; +// tsk_buffer_append(output, username->value, tsk_strlen(username->value)); +// return 0; +// } +// +// +// /* RFC 5389 - MESSAGE-INTEGRITY*/ +// case stun_message_integrity: { +// tnet_stun_attribute_integrity_t *integrity = (tnet_stun_attribute_integrity_t*)attribute; +// tsk_buffer_append(output, integrity->sha1digest, TSK_SHA1_DIGEST_SIZE); +// return 0; +// } +// +// /* RFC 5389 - 15.5. FINGERPRINT*/ +// case stun_fingerprint: { +// uint32_t fingerprint = /*tnet_htonl*/(((tnet_stun_attribute_fingerprint_t*)attribute)->value); +// tsk_buffer_append(output, &fingerprint, 4); +// return 0; +// } +// +// /* RFC 5389 - 15.6. ERROR-CODE*/ +// case stun_error_code: { +// uint32_t u32 = 0; +// tnet_stun_attribute_errorcode_t *errorcode = (tnet_stun_attribute_errorcode_t*)attribute; +// u32 |= (errorcode->_class & 0x07) << 8; +// u32 |= errorcode->number; +// u32 = tnet_htonl(u32); +// tsk_buffer_append(output, &u32, 4); +// tsk_buffer_append(output, errorcode->reason_phrase, tsk_strlen(errorcode->reason_phrase)); +// return 0; +// } +// +// /* RFC 5389 - 15.7. REALM*/ +// case stun_realm: { +// tnet_stun_attribute_realm_t *realm = (tnet_stun_attribute_realm_t*)attribute; +// tsk_buffer_append(output, realm->value, tsk_strlen(realm->value)); +// return 0; +// } +// +// /* RFC 5389 - 15.8. NONCE*/ +// case stun_nonce: { +// tnet_stun_attribute_nonce_t *nonce = (tnet_stun_attribute_nonce_t*)attribute; +// tsk_buffer_append(output, nonce->value, tsk_strlen(nonce->value)); +// return 0; +// } +// +// /* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES*/ +// case stun_unknown_attributes: { +// TSK_DEBUG_ERROR("NOT IMPLEMENTED"); +// return -3; +// } +// +// /* RFC 5389 - 15.10. SOFTWARE */ +// case stun_software: { +// tnet_stun_attribute_software_t *software = (tnet_stun_attribute_software_t*)attribute; +// tsk_buffer_append(output, software->value, tsk_strlen(software->value)); +// return 0; +// } +// +// /* RFC 5389 - 15.11. ALTERNATE-SERVER */ +// case stun_alternate_server: { +// TSK_DEBUG_ERROR("NOT IMPLEMENTED"); +// return -3; +// } +// /* draft-ietf-behave-turn-16 - */ +// case stun_channel_number: +// case stun_lifetime: +// case stun_reserved2: +// case stun_xor_peer_address: +// case stun_data: +// case stun_xor_relayed_address: +// case stun_even_port: +// case stun_requested_transport: +// case stun_dont_fragment: +// case stun_reserved3: +// case stun_reservation_token: { +// return -1;//tnet_turn_attribute_serialize(attribute, output); +// } +// +// +// /* RFC 5245 - 19.1. PRIORITY */ +// case stun_ice_priority: { +// uint32_t value = tnet_htonl(((tnet_stun_attribute_ice_priority_t*)attribute)->value); +// tsk_buffer_append(output, &value, 4); +// return 0; +// } +// /* RFC 5245 - 19.1. USE_CANDIDATE */ +// case stun_ice_use_candidate: { +// // no body +// return 0; +// } +// /* RFC 5245 - 19.1. ICE_CONTROLLED */ +// case stun_ice_controlled: { +// uint64_t value = ((tnet_stun_attribute_ice_controlled_t*)attribute)->value; +// value = ((((uint64_t)tnet_htonl(value >> 32)) << 32) | ((uint64_t)tnet_htonl(value & 0xFFFFFFFF))); +// tsk_buffer_append(output, &value, 8); +// return 0; +// } +// /* RFC 5245 - 19.1. ICE_CONTROLLING */ +// case stun_ice_controlling: { +// uint64_t value = ((tnet_stun_attribute_ice_controlling_t*)attribute)->value; +// value = ((((uint64_t)tnet_htonl(value >> 32)) << 32) | ((uint64_t)tnet_htonl(value & 0xFFFFFFFF))); +// tsk_buffer_append(output, &value, 8); +// return 0; +// } +// +// default: +// return -2; +// } +//} +// +///**@ingroup tnet_stun_group +//* Pads a STUN attribute to align it on 4 octets. +//* @param attribute The STUN attribute to pad. +//* @param output The output buffer into which to put zeros. +//*/ +//void tnet_stun_attribute_pad(const tnet_stun_attr_t* attribute, tsk_buffer_t *output) +//{ +// if(attribute->length & 0x03) { +// static uint32_t zeros = 0x00000000; +// tsk_buffer_append(output, &zeros, 4-(attribute->length & 0x03)); +// } +//} +// +// +// +// +////================================================================================================= +//// [[RFC 5389 - 15. STUN Attributes]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attr_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_dtor(tsk_object_t * self) +//{ +// tnet_stun_attr_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_def_s = { +// sizeof(tnet_stun_attr_t), +// tnet_stun_attribute_ctor, +// tnet_stun_attribute_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_def_t = &tnet_stun_attribute_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.1. MAPPED-ADDRESS]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_mapped_addr_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_mapped_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 */ +// +// attribute->family = (tnet_stun_addr_family_t) (*(payloadPtr++)); +// attribute->port = tnet_ntohs_2(payloadPtr); +// 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; +// +// for(i=0; i<addr_size; i+=4) { +// // ntohl() not needed : byte per byte to avoid endianness problem +// attribute->address[i] = payloadPtr[0], +// attribute->address[i+1] = payloadPtr[1], +// attribute->address[i+2] = payloadPtr[2], +// attribute->address[i+3] = payloadPtr[3]; +// payloadPtr+=4; +// } +// } +// else { +// TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family); +// } +// } +// } +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_mapped_address; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_mapped_addr_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_mapped_addr_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_mapped_addr_def_s = { +// sizeof(tnet_stun_attribute_mapped_addr_t), +// tnet_stun_attribute_mapped_addr_ctor, +// tnet_stun_attribute_mapped_addr_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_mapped_addr_def_t = &tnet_stun_attribute_mapped_addr_def_s; +// +////================================================================================================= +//// [[RFC 5389 - 15.2. XOR-MAPPED-ADDRESS]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_xmapped_addr_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_xmapped_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 */ +// +// attribute->family = (tnet_stun_addr_family_t)(*(payloadPtr++)); +// +// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS +// X-Port is computed by taking the mapped port in host byte order, +// XOR'ing it with the most significant 16 bits of the magic cookie, and +// then the converting the result to network byte order. +// */ +// attribute->xport = tnet_ntohs_2(payloadPtr); +// attribute->xport ^= 0x2112; +// payloadPtr+=2; +// +// +// { /*=== Compute IP address */ +// +// /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS +// If the IP address family is IPv4, X-Address is computed by taking the mapped IP +// address in host byte order, XOR'ing it with the magic cookie, and +// converting the result to network byte order. +// */ +// 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_ntohl(tnet_ntohl_2(payloadPtr) ^ kStunMagicCookieLong); +// memcpy(&attribute->xaddress[i], &addr, 4); +// payloadPtr+=4; +// } +// } +// else { +// TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family); +// } +// } +// } +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_mapped_address; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_xmapped_addr_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_xmapped_addr_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_xmapped_addr_def_s = { +// sizeof(tnet_stun_attribute_xmapped_addr_t), +// tnet_stun_attribute_xmapped_addr_ctor, +// tnet_stun_attribute_xmapped_addr_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_xmapped_addr_def_t = &tnet_stun_attribute_xmapped_addr_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.3. USERNAME]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_username_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_username_t *attribute = self; +// if(attribute) { +// const void *payload = va_arg(*app, const void*); +// tsk_size_t payload_size = va_arg(*app, tsk_size_t); +// +// attribute->value = tsk_strndup(payload, payload_size); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_username; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_username_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_username_t *attribute = self; +// if(attribute) { +// TSK_FREE(attribute->value); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_username_def_s = { +// sizeof(tnet_stun_attribute_username_t), +// tnet_stun_attribute_username_ctor, +// tnet_stun_attribute_username_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_username_def_t = &tnet_stun_attribute_username_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.4. MESSAGE-INTEGRITY]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_integrity_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_integrity_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_size == TSK_SHA1_DIGEST_SIZE) { +// memcpy(attribute->sha1digest, payload, TSK_SHA1_DIGEST_SIZE); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_message_integrity; +// TNET_STUN_ATTRIBUTE(attribute)->length = TSK_SHA1_DIGEST_SIZE; +// } +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_integrity_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_integrity_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_integrity_def_s = { +// sizeof(tnet_stun_attribute_integrity_t), +// tnet_stun_attribute_integrity_ctor, +// tnet_stun_attribute_integrity_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_integrity_def_t = &tnet_stun_attribute_integrity_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.5. FINGERPRINT]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_fingerprint_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_fingerprint_t *attribute = self; +// if(attribute) { +// attribute->value = va_arg(*app, uint32_t); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_fingerprint; +// TNET_STUN_ATTRIBUTE(attribute)->length = 4; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_fingerprint_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_fingerprint_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_fingerprint_def_s = { +// sizeof(tnet_stun_attribute_fingerprint_t), +// tnet_stun_attribute_fingerprint_ctor, +// tnet_stun_attribute_fingerprint_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_fingerprint_def_t = &tnet_stun_attribute_fingerprint_def_s; +// +// +// +////================================================================================================= +//// [[RFC 5389 - 15.6. ERROR-CODE]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_errorcode_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_errorcode_t *attribute = self; +// if(attribute) { +// const uint8_t *payload = (const uint8_t*)va_arg(*app, const void*); +// tsk_size_t payload_size = va_arg(*app, tsk_size_t); +// +// if(payload_size >4) { +// uint32_t code = tnet_htonl_2(payload); +// payload += 4; +// +// attribute->_class = code >>8; +// attribute->number = (code & 0xFF); +// attribute->reason_phrase = tsk_strndup((const char*)payload, (payload_size-4)); +// } +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_error_code; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_errorcode_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_errorcode_t *attribute = self; +// if(attribute) { +// TSK_FREE(attribute->reason_phrase); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_errorcode_def_s = { +// sizeof(tnet_stun_attribute_errorcode_t), +// tnet_stun_attribute_errorcode_ctor, +// tnet_stun_attribute_errorcode_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_errorcode_def_t = &tnet_stun_attribute_errorcode_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.7. REALM]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_realm_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_realm_t *attribute = self; +// if(attribute) { +// const void *payload = va_arg(*app, const void*); +// tsk_size_t payload_size = va_arg(*app, tsk_size_t); +// +// attribute->value = tsk_strndup(payload, payload_size); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_realm; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_realm_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_realm_t *attribute = self; +// if(attribute) { +// TSK_FREE(attribute->value); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_realm_def_s = { +// sizeof(tnet_stun_attribute_realm_t), +// tnet_stun_attribute_realm_ctor, +// tnet_stun_attribute_realm_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_realm_def_t = &tnet_stun_attribute_realm_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.8. NONCE]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_nonce_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_nonce_t *attribute = self; +// if(attribute) { +// const void *payload = va_arg(*app, const void*); +// tsk_size_t payload_size = va_arg(*app, tsk_size_t); +// +// attribute->value = tsk_strndup(payload, payload_size); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_nonce; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_nonce_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_nonce_t *attribute = self; +// if(attribute) { +// TSK_FREE(attribute->value); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_nonce_def_s = { +// sizeof(tnet_stun_attribute_nonce_t), +// tnet_stun_attribute_nonce_ctor, +// tnet_stun_attribute_nonce_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_nonce_def_t = &tnet_stun_attribute_nonce_def_s; +// +// +////================================================================================================= +//// [[RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_unknowns_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_unknowns_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_unknown_attributes; +// attribute->value = tsk_buffer_create_null(); +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_unknowns_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_unknowns_t *attribute = self; +// if(attribute) { +// TSK_OBJECT_SAFE_FREE(attribute->value); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_unknowns_def_s = { +// sizeof(tnet_stun_attribute_unknowns_t), +// tnet_stun_attribute_unknowns_ctor, +// tnet_stun_attribute_unknowns_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_unknowns_def_t = &tnet_stun_attribute_unknowns_def_s; +// +////================================================================================================= +//// [[RFC 5389 - 15.10. SOFTWARE]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_software_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_software_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_software; +// +// attribute->value = tsk_strndup(payload, payload_size); +// TNET_STUN_ATTRIBUTE(attribute)->length = tsk_strlen(attribute->value); +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_software_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_software_t *attribute = self; +// if(attribute) { +// TSK_FREE(attribute->value); +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_software_def_s = { +// sizeof(tnet_stun_attribute_software_t), +// tnet_stun_attribute_software_ctor, +// tnet_stun_attribute_software_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_software_def_t = &tnet_stun_attribute_software_def_s; +// +////================================================================================================= +//// [[RFC 5389 - 15.11. ALTERNATE-SERVER]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_altserver_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_altserver_t *attribute = self; +// if(attribute) { +// const void *payload = va_arg(*app, const void*); +// tsk_size_t payload_size = va_arg(*app, tsk_size_t); +// +// const uint8_t *payloadPtr = (const uint8_t*)payload; +// payloadPtr += 1; /* Ignore first 8bits */ +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_alternate_server; +// TNET_STUN_ATTRIBUTE(attribute)->length = payload_size; +// +// attribute->family = (tnet_stun_addr_family_t) (*(payloadPtr++)); +// attribute->port = tnet_ntohs_2(payloadPtr); +// payloadPtr+=2; +// +// if(attribute->family == stun_ipv4) { +// uint32_t addr = tnet_htonl_2(payloadPtr); +// memcpy(attribute->server, &addr, 4); +// payloadPtr+=4; +// } +// else if(attribute->family == stun_ipv6) { +// TSK_DEBUG_ERROR("IPv6 not supported yet."); +// } +// else { +// TSK_DEBUG_ERROR("UNKNOWN FAMILY."); +// } +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_altserver_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_altserver_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_altserver_def_s = { +// sizeof(tnet_stun_attribute_altserver_t), +// tnet_stun_attribute_altserver_ctor, +// tnet_stun_attribute_altserver_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_altserver_def_t = &tnet_stun_attribute_altserver_def_s; +// +// +////================================================================================================= +//// [[RFC 5245 - 19.1. PRIORITY]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_ice_priority_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_ice_priority_t *attribute = self; +// if(attribute) { +// attribute->value = va_arg(*app, uint32_t); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_priority; +// TNET_STUN_ATTRIBUTE(attribute)->length = 4; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_ice_priority_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_ice_priority_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_ice_priority_def_s = { +// sizeof(tnet_stun_attribute_ice_priority_t), +// tnet_stun_attribute_ice_priority_ctor, +// tnet_stun_attribute_ice_priority_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_ice_priority_def_t = &tnet_stun_attribute_ice_priority_def_s; +// +// +////================================================================================================= +//// [[RFC 5245 - 19.1. USE-CANDIDATE]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_ice_use_candidate_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_ice_use_candidate_t *attribute = self; +// if(attribute) { +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_use_candidate; +// TNET_STUN_ATTRIBUTE(attribute)->length = 0; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_ice_use_candidate_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_ice_use_candidate_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_ice_use_candidate_def_s = { +// sizeof(tnet_stun_attribute_ice_use_candidate_t), +// tnet_stun_attribute_ice_use_candidate_ctor, +// tnet_stun_attribute_ice_use_candidate_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_ice_use_candidate_def_t = &tnet_stun_attribute_ice_use_candidate_def_s; +// +// +////================================================================================================= +//// [[RFC 5245 - 19.1. ICE-CONTROLLED]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_ice_controlled_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_ice_controlled_t *attribute = self; +// if(attribute) { +// attribute->value = va_arg(*app, uint64_t); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_controlled; +// TNET_STUN_ATTRIBUTE(attribute)->length = 8; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_ice_controlled_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_ice_controlled_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_ice_controlled_def_s = { +// sizeof(tnet_stun_attribute_ice_controlled_t), +// tnet_stun_attribute_ice_controlled_ctor, +// tnet_stun_attribute_ice_controlled_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_ice_controlled_def_t = &tnet_stun_attribute_ice_controlled_def_s; +// +// +// +////================================================================================================= +//// [[RFC 5245 - 19.1. ICE-CONTROLLING]] object definition +//// +//static tsk_object_t* tnet_stun_attribute_ice_controlling_ctor(tsk_object_t * self, va_list * app) +//{ +// tnet_stun_attribute_ice_controlling_t *attribute = self; +// if(attribute) { +// attribute->value = va_arg(*app, uint64_t); +// +// TNET_STUN_ATTRIBUTE(attribute)->type = stun_ice_controlling; +// TNET_STUN_ATTRIBUTE(attribute)->length = 8; +// } +// return self; +//} +// +//static tsk_object_t* tnet_stun_attribute_ice_controlling_dtor(tsk_object_t * self) +//{ +// tnet_stun_attribute_ice_controlling_t *attribute = self; +// if(attribute) { +// } +// return self; +//} +// +//static const tsk_object_def_t tnet_stun_attribute_ice_controlling_def_s = { +// sizeof(tnet_stun_attribute_ice_controlling_t), +// tnet_stun_attribute_ice_controlling_ctor, +// tnet_stun_attribute_ice_controlling_dtor, +// tsk_null, +//}; +//const tsk_object_def_t *tnet_stun_attribute_ice_controlling_def_t = &tnet_stun_attribute_ice_controlling_def_s; diff --git a/tinyNET/src/stun/tnet_stun_attribute.h b/tinyNET/src/stun/tnet_stun_attribute.h new file mode 100644 index 0000000..d9e0de7 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_attribute.h @@ -0,0 +1,356 @@ +///* +//* 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_attribute.h +// * @brief STUN2(RFC 5389) attribute parser. +// * +// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> +// * +// +// */ +//#ifndef TNET_STUN_ATTRIBUTE_H +//#define TNET_STUN_ATTRIBUTE_H +// +//#include "tinynet_config.h" +// +//#include "tnet_types.h" +// +//#include "tsk_object.h" +//#include "tsk_buffer.h" +//#include "tsk_sha1.h" +// +///**@ingroup tnet_stun_group +//* @def TNET_STUN_ATTRIBUTE +//* Converts (cast) any STUN attribute to @ref tnet_stun_attr_t pointer. +//* @param self The attribute to convert (cast). +//* @retval A pointer to @ref tnet_stun_attr_t object. +//*/ +//TNET_BEGIN_DECLS +// +//#define TNET_STUN_ATTRIBUTE(self) ((tnet_stun_attr_t*)(self)) +// +///**@ingroup tnet_stun_group +// * STUN IP family as per RFC 5389 subclause 15.1. +//**/ +//typedef enum tnet_stun_addr_family_e { +// stun_ipv4 = 0x01, +// stun_ipv6 = 0x02 +//} +//tnet_stun_addr_family_t; +// +///**@ingroup tnet_stun_group +// * STUN attribute types as per RFC 5389 subclause 18.2. +//**/ +//typedef enum tnet_stun_attr_type_e { +// /* === RFC 5389 - Comprehension-required range (0x0000-0x7FFF) */ +// stun_reserved = 0x0000, /**< (Reserved) */ +// stun_mapped_address = 0x0001, /**< http://tools.ietf.org/html/rfc5389#page-32 */ +// stun_response_address = 0x0002, /**< (Reserved; was RESPONSE-ADDRESS) */ +// stun_change_address = 0x0003, /**< (Reserved; was CHANGE-ADDRESS) */ +// stun_source_address = 0x0004, /**< (Reserved; was SOURCE-ADDRESS) */ +// stun_changed_address = 0x0005, /**< (Reserved; was CHANGED-ADDRESS) */ +// stun_username = 0x0006, /**< http://tools.ietf.org/html/rfc5389#page-34 */ +// stun_password = 0x0007, /**< (Reserved; was PASSWORD) */ +// stun_message_integrity = 0x0008, /**< http://tools.ietf.org/html/rfc5389#page-34 */ +// stun_error_code = 0x0009, /**< http://tools.ietf.org/html/rfc5389#page-36 */ +// stun_unknown_attributes = 0x000A, /**< http://tools.ietf.org/html/rfc5389#page-38 */ +// stun_reflected_from = 0x000B, /**< (Reserved; was REFLECTED-FROM) */ +// stun_realm = 0x0014, /**< http://tools.ietf.org/html/rfc5389#page-38 */ +// stun_nonce = 0x0015, /**< http://tools.ietf.org/html/rfc5389#page-38 */ +// stun_xor_mapped_address = 0x0020, /**< http://tools.ietf.org/html/rfc5389#page-33 */ +// +// /* === RFC 5389 - Comprehension-optional range (0x8000-0xFFFF) */ +// stun_software = 0x8022, /**< http://tools.ietf.org/html/rfc5389#page-39 */ +// stun_alternate_server = 0x8023, /**< http://tools.ietf.org/html/rfc5389#page-39 */ +// stun_fingerprint = 0x8028, /**< http://tools.ietf.org/html/rfc5389#page-36 */ +// +// /* === draft-ietf-behave-turn-16 */ +// stun_channel_number = 0x000C, /**< draft-ietf-behave-turn-16 - CHANNEL-NUMBER */ +// stun_lifetime = 0x000D, /**< draft-ietf-behave-turn-16 - LIFETIME */ +// stun_reserved2 = 0x0010, /**< draft-ietf-behave-turn-16 - Reserved (was BANDWIDTH) */ +// stun_xor_peer_address = 0x0012, /**< draft-ietf-behave-turn-16 - XOR-PEER-ADDRESS */ +// stun_data = 0x0013, /**< draft-ietf-behave-turn-16 - DATA */ +// stun_xor_relayed_address = 0x0016, /**< draft-ietf-behave-turn-16 - XOR-RELAYED-ADDRESS */ +// stun_even_port = 0x0018, /**< draft-ietf-behave-turn-16 - EVEN-PORT */ +// stun_requested_transport = 0x0019, /**< draft-ietf-behave-turn-16 - REQUESTED-TRANSPORT */ +// stun_dont_fragment = 0x001A, /**< draft-ietf-behave-turn-16 - DONT-FRAGMENT */ +// stun_reserved3 = 0x0021, /**< draft-ietf-behave-turn-16 - Reserved (was TIMER-VAL) */ +// stun_reservation_token = 0x0022, /**< draft-ietf-behave-turn-16 - RESERVATION-TOKEN */ +// +// /* RFC 5245 */ +// stun_ice_priority = 0x0024, /**< 21.2. STUN Attributes */ +// stun_ice_use_candidate = 0x0025, /**< 21.2. STUN Attributes */ +// stun_ice_controlled = 0x8029, /**< 21.2. STUN Attributes */ +// stun_ice_controlling = 0x802A, /**< 21.2. STUN Attributes */ +//} +//tnet_stun_attr_type_t; +// +// +///**@ingroup tnet_stun_group +// RFC 5389 - 15. STUN Attributes +//*/ +//typedef struct tnet_stun_attribute_s { +// TSK_DECLARE_OBJECT; +// /* +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Type | Length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Value (variable) .... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// tnet_stun_attr_type_t type; +// uint16_t length; +//} +//tnet_stun_attr_t; +// +//typedef tsk_list_t tnet_stun_attributes_L_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_def_t; +// +//#define TNET_STUN_DECLARE_ATTRIBUTE tnet_stun_attr_t attribute +// +// +///**@ingroup tnet_stun_group +// *RFC 5389 - 15.1. MAPPED-ADDRESS +// */ +//typedef struct tnet_stun_attribute_mapped_addr_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// /* +// 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 0 0 0 0 0 0| Family | Port | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | | +// | Address (32 bits or 128 bits) | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// tnet_stun_addr_family_t family; +// uint16_t port; +// uint8_t address[16]; +//} +//tnet_stun_attribute_mapped_addr_t; +// +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_mapped_addr_def_t; +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS +//*/ +//typedef struct tnet_stun_attribute_xmapped_addr_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// /* +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |x x x x x x x x| Family | X-Port | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | X-Address (Variable) +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// tnet_stun_addr_family_t family; +// uint16_t xport; +// uint8_t xaddress[16]; +//} +//tnet_stun_attribute_xmapped_addr_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_xmapped_addr_def_t; +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.3. USERNAME. +//*/ +//typedef struct tnet_stun_attribute_username_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// char* value; +//} +//tnet_stun_attribute_username_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_username_def_t; +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.4. MESSAGE-INTEGRITY. +//*/ +//typedef struct tnet_stun_attribute_integrity_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// tsk_sha1digest_t sha1digest; +//} +//tnet_stun_attribute_integrity_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_integrity_def_t; +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.5. FINGERPRINT. +//*/ +//typedef struct tnet_stun_attribute_fingerprint_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// uint32_t value; +//} +//tnet_stun_attribute_fingerprint_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_fingerprint_def_t; +// +///**@ingroup tnet_stun_group +// *RFC 5389 - 15.6. ERROR-CODE +//*/ +//typedef struct tnet_stun_attribute_errorcode_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// /* +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Reserved, should be 0 |Class| Number | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | Reason Phrase (variable) .. +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// uint8_t _class; +// uint8_t number; +// char* reason_phrase; +//} +//tnet_stun_attribute_errorcode_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_errorcode_def_t; +// +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.7. REALM. */ +//typedef struct tnet_stun_attribute_realm_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// char* value; +//} +//tnet_stun_attribute_realm_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_realm_def_t; +// +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.8. NONCE. */ +//typedef struct tnet_stun_attribute_nonce_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// char* value; +//} +//tnet_stun_attribute_nonce_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_nonce_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.9. UNKNOWN-ATTRIBUTES. */ +//typedef struct tnet_stun_attribute_unknowns_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// tsk_buffer_t *value; +//} +//tnet_stun_attribute_unknowns_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_unknowns_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.10. SOFTWARE. */ +//typedef struct tnet_stun_attribute_software_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// char *value; +//} +//tnet_stun_attribute_software_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_software_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5389 - 15.11. ALTERNATE-SERVER. */ +//typedef struct tnet_stun_attribute_altserver_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// +// tnet_stun_addr_family_t family; +// uint16_t port; +// uint8_t server[128]; +//} +//tnet_stun_attribute_altserver_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_altserver_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. New Attributes */ +//typedef struct tnet_stun_attribute_ice_priority_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// uint32_t value; +//} +//tnet_stun_attribute_ice_priority_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_priority_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. New Attributes */ +//typedef struct tnet_stun_attribute_ice_use_candidate_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +//} +//tnet_stun_attribute_ice_use_candidate_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_use_candidate_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. New Attributes */ +//typedef struct tnet_stun_attribute_ice_controlled_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// uint64_t value; +//} +//tnet_stun_attribute_ice_controlled_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_controlled_def_t; +// +///**@ingroup tnet_stun_group +//* RFC 5245 - 19.1. New Attributes */ +//typedef struct tnet_stun_attribute_ice_controlling_s { +// TNET_STUN_DECLARE_ATTRIBUTE; +// uint64_t value; +//} +//tnet_stun_attribute_ice_controlling_t; +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_attribute_ice_controlling_def_t; +// +//tnet_stun_attr_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size); +//int tnet_stun_attribute_serialize(const tnet_stun_attr_t* attribute, tsk_buffer_t *output); +//void tnet_stun_attribute_pad(const tnet_stun_attr_t* attribute, tsk_buffer_t *output); +// +// +// +// +//tnet_stun_attr_t* tnet_stun_attribute_create(); +//TINYNET_API tnet_stun_attribute_mapped_addr_t* tnet_stun_attribute_mapped_address_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_xmapped_addr_t* tnet_stun_attribute_xmapped_address_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_username_t* tnet_stun_attribute_username_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_integrity_t* tnet_stun_attribute_integrity_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_fingerprint_t* tnet_stun_attribute_fingerprint_create(uint32_t fingerprint); +//TINYNET_API tnet_stun_attribute_errorcode_t* tnet_stun_attribute_errorcode_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_realm_t* tnet_stun_attribute_realm_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_nonce_t* tnet_stun_attribute_nonce_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_unknowns_t* tnet_stun_attribute_unknowns_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_software_t* tnet_stun_attribute_software_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_altserver_t* tnet_stun_attribute_altserver_create(const void* payload, tsk_size_t payload_size); +//TINYNET_API tnet_stun_attribute_ice_priority_t* tnet_stun_attribute_ice_priority_create(uint32_t value); +//TINYNET_API tnet_stun_attribute_ice_use_candidate_t* tnet_stun_attribute_ice_use_candidate_create(); +//TINYNET_API tnet_stun_attribute_ice_controlled_t* tnet_stun_attribute_ice_controlled_create(uint64_t value); +//TINYNET_API tnet_stun_attribute_ice_controlling_t* tnet_stun_attribute_ice_controlling_create(uint64_t value); +// +// +//TNET_END_DECLS +// +//#endif /* TNET_STUN_ATTRIBUTE_H */ +// diff --git a/tinyNET/src/stun/tnet_stun_binding.c b/tinyNET/src/stun/tnet_stun_binding.c new file mode 100644 index 0000000..6455751 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_binding.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stun/tnet_stun_binding.h" +#include "stun/tnet_stun_pkt.h" +#include "stun/tnet_stun_attr.h" +#include "tnet_utils.h" + +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +int tnet_stun_binding_create(tnet_fd_t fd, enum tnet_socket_type_e socket_type, const char* pc_server_address, tnet_port_t server_port, const char* pc_username, const char* pc_password, tnet_stun_binding_t** pp_bind) +{ + extern const tsk_object_def_t *tnet_stun_binding_def_t; + static long __unique_id = 0; + + if (!pp_bind) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(*pp_bind = tsk_object_new(tnet_stun_binding_def_t))) { + TSK_DEBUG_ERROR("Failed to create STUN binding object"); + return -2; + } + tsk_atomic_inc(&__unique_id); + (*pp_bind)->id = __unique_id; + (*pp_bind)->localFD = fd; + (*pp_bind)->socket_type = socket_type; + (*pp_bind)->p_username = tsk_strdup(pc_username); + (*pp_bind)->p_password = tsk_strdup(pc_password); + + if (pc_server_address && server_port) { + int ret; + if ((ret = tnet_sockaddr_init(pc_server_address, server_port, socket_type, &(*pp_bind)->addr_server))) { + TSK_OBJECT_SAFE_FREE((*pp_bind)); + TSK_DEBUG_ERROR("Failed to init STUN server address"); + return ret; + } + } + return 0; +} + +int tnet_stun_binding_create_req(const struct tnet_stun_binding_s* pc_self, struct tnet_stun_pkt_s **pp_req) +{ + int ret; + if (!pc_self || !pp_req) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + if ((ret = tnet_stun_pkt_create_empty(tnet_stun_pkt_type_binding_request, pp_req))) { + TSK_DEBUG_ERROR("Failed to create STUN Bind request"); + goto bail; + } + // add attributes + (*pp_req)->opt.dontfrag = 0; + ret = tnet_stun_pkt_attrs_add(*pp_req, + TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(kStunSoftware), + TNET_STUN_PKT_ATTR_ADD_NULL()); + if (ret) { + goto bail; + } + if (pc_self->p_username && pc_self->p_realm && pc_self->p_nonce) { + if ((ret = tnet_stun_pkt_auth_prepare(*pp_req, pc_self->p_username, pc_self->p_password, pc_self->p_realm, pc_self->p_nonce))) { + goto bail; + } + } + +bail: + if (ret) { + TSK_OBJECT_SAFE_FREE(*pp_req); + } + return ret; +} + +static tsk_object_t* tnet_stun_binding_ctor(tsk_object_t * self, va_list * app) +{ + tnet_stun_binding_t *p_bind = (tnet_stun_binding_t *)self; + if (p_bind) { + } + return self; +} +static tsk_object_t* tnet_stun_binding_dtor(tsk_object_t * self) +{ + tnet_stun_binding_t *p_bind = (tnet_stun_binding_t *)self; + if (p_bind) { + TSK_DEBUG_INFO("*** STUN BINDING destroyed ***"); + TSK_FREE(p_bind->p_username); + TSK_FREE(p_bind->p_password); + TSK_FREE(p_bind->p_realm); + TSK_FREE(p_bind->p_nonce); + + TSK_OBJECT_SAFE_FREE(p_bind->p_maddr); + TSK_OBJECT_SAFE_FREE(p_bind->p_xmaddr); + } + return self; +} +static int tnet_stun_binding_cmp(const tsk_object_t *_bind1, const tsk_object_t *_bind2) +{ + const tnet_stun_binding_t *pc_bind1 = (const tnet_stun_binding_t *)_bind1; + const tnet_stun_binding_t *pc_bind2 = (const tnet_stun_binding_t *)_bind2; + + return (pc_bind1 && pc_bind2) ? (int)(pc_bind1->id - pc_bind2->id) : (int)(pc_bind1 - pc_bind2); +} +static const tsk_object_def_t tnet_stun_binding_def_s = { + sizeof(tnet_stun_binding_t), + tnet_stun_binding_ctor, + tnet_stun_binding_dtor, + tnet_stun_binding_cmp, +}; +const tsk_object_def_t *tnet_stun_binding_def_t = &tnet_stun_binding_def_s; diff --git a/tinyNET/src/stun/tnet_stun_binding.h b/tinyNET/src/stun/tnet_stun_binding.h new file mode 100644 index 0000000..d7e2ae4 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_binding.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TNET_STUN_BINDING_H +#define TNET_STUN_BINDING_H + +#include "tinynet_config.h" +#include "tnet_socket.h" +#include "stun/tnet_stun_types.h" +#include "stun/tnet_stun_attr.h" + +#include "tsk_object.h" +#include "tsk_list.h" + +TNET_BEGIN_DECLS + +struct tnet_stun_pkt_s; + +typedef struct tnet_stun_binding_s { + TSK_DECLARE_OBJECT; + + //! A unique id to identify this binding. + tnet_stun_binding_id_t id; + + //! The username to authenticate to the STUN server. + char* p_username; + //! The password to authenticate to the STUN server. + char* p_password; + //! The realm. + char* p_realm; + //! The nonce. + char* p_nonce; + //! Local file descriptor for which to get server reflexive address. + tnet_fd_t localFD; + //! The type of the bound socket. + enum tnet_socket_type_e socket_type; + //! The address of the STUN server. + struct sockaddr_storage addr_server; + //! Server reflexive address of the local socket(STUN1 as per RFC 3489). + struct tnet_stun_attr_address_s *p_maddr; + //! XORed server reflexive address (STUN2 as per RFC 5389). + struct tnet_stun_attr_address_s *p_xmaddr; +} +tnet_stun_binding_t; +typedef tsk_list_t tnet_stun_bindings_L_t; + +int tnet_stun_binding_create(tnet_fd_t fd, enum tnet_socket_type_e socket_type, const char* pc_server_address, tnet_port_t server_port, const char* pc_username, const char* pc_password, tnet_stun_binding_t** pp_bind); +int tnet_stun_binding_create_req(const struct tnet_stun_binding_s* pc_self, struct tnet_stun_pkt_s **pp_req); + +TNET_END_DECLS + +#endif /* TNET_STUN_BINDING_H */ diff --git a/tinyNET/src/stun/tnet_stun_message.c b/tinyNET/src/stun/tnet_stun_message.c new file mode 100644 index 0000000..25d29a5 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_message.c @@ -0,0 +1,495 @@ +///* +//* 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 0 +// if(self->fingerprint) { +// length += (2/* Type */ + 2 /* Length */+ 4 /* FINGERPRINT VALUE*/); +// } +//#endif +// +// 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; +// diff --git a/tinyNET/src/stun/tnet_stun_message.h b/tinyNET/src/stun/tnet_stun_message.h new file mode 100644 index 0000000..70660f5 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_message.h @@ -0,0 +1,246 @@ +///* +//* 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.h +// * @brief STUN2 (RFC 5389) message parser. +// * +// * @author Mamadou Diop <diopmamadou(at)doubango[dot]org> +// * +// +// */ +//#ifndef TNET_STUN_MESSAGE_H +//#define TNET_STUN_MESSAGE_H +// +//#include "tinynet_config.h" +//#include "stun/tnet_stun_attribute.h" +// +//#include "tsk_buffer.h" +// +//TNET_BEGIN_DECLS +// +//#define TNET_STUN_CLASS_REQUEST_MASK (0x0000) +//#define TNET_STUN_CLASS_INDICATION_MASK (0x0010) +//#define TNET_STUN_CLASS_SUCCESS_MASK (0x0100) +//#define TNET_STUN_CLASS_ERROR_MASK (0x0110) +// +///**@ingroup tnet_stun_group +//* @def TNET_STUN_MESSAGE_IS_REQUEST +//* Checks whether the STUN message is a request or not. +//*/ +///**@ingroup tnet_stun_group +//* @def TNET_STUN_MESSAGE_IS_INDICATION +//* Checks whether the STUN message is an indicaton message or not. +//*/ +///**@ingroup tnet_stun_group +//* @def TNET_STUN_PKT_RESP_IS_SUCCESS +//* Checks whether the STUN message is a success response or not. +//*/ +///**@ingroup tnet_stun_group +//* @def TNET_STUN_PKT_RESP_IS_ERROR +//* Checks whether the STUN message is an error response or not. +//*/ +//#define TNET_STUN_MESSAGE_IS_REQUEST(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_REQUEST_MASK)) +//#define TNET_STUN_MESSAGE_IS_RESPONSE(self) (TNET_STUN_PKT_RESP_IS_SUCCESS((self)) || TNET_STUN_PKT_RESP_IS_ERROR((self))) +//#define TNET_STUN_MESSAGE_IS_INDICATION(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_INDICATION_MASK)) +//#define TNET_STUN_PKT_RESP_IS_SUCCESS(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_SUCCESS_MASK)) +//#define TNET_STUN_PKT_RESP_IS_ERROR(self) ((self) && (((self)->type & 0x0110) == TNET_STUN_CLASS_ERROR_MASK)) +// +///**@ingroup tnet_stun_group +// * Checks if the pointer to the buffer hold a STUN header by checking that it starts with 0b00 and contain the magic cookie. +// * As per RFC 5389 subclause 19: Explicitly point out that the most significant 2 bits of STUN are +// * 0b00, allowing easy differentiation with RTP packets when used with ICE. +// * As per RFC 5389 subclause 6: The magic cookie field MUST contain the fixed value 0x2112A442 in +// * network byte order. +// * +// * @param PU8 The pointer to the buffer holding the STUN raw data. +//**/ +//#define TNET_STUN_BUFF_IS_STUN2(PU8, SIZE) \ +// ( \ +// ((PU8)) && \ +// ((SIZE) >= kStunAttrHdrSizeInOctets) && \ +// (((PU8)[0] & 0xc0) == 0x00) && \ +// ( PU8[4] == 0x21 && PU8[5] == 0x12 && PU8[6] == 0xA4 && PU8[7] == 0x42 ) \ +// ) +//#define TNET_IS_STUN2 TNET_STUN_BUFF_IS_STUN2 // for backward compatibility +// +///**@ingroup tnet_stun_group +// * STUN trasactionn ID size (96bits = 12bytes). +//*/ +//#define TNET_STUN_TRANSACID_SIZE 12 +// +///**@ingroup tnet_stun_group +// * Defines an alias representing the STUN transaction id type. +//**/ +//typedef uint8_t tnet_stun_transac_id_t[TNET_STUN_TRANSACID_SIZE]; +// +///**@ingroup tnet_stun_group +// * List of all supported STUN classes as per RFC 5389 subcaluse 6. +//**/ +//typedef enum tnet_stun_class_type_e { +// stun_class_request = 0x00, /**< Request class: 0b00 */ +// stun_class_indication = 0x01, /**< Indication class: 0b01 */ +// stun_class_success_response = 0x02, /**< Success response class: 0b10 */ +// stun_class_error_response = 0x03, /**< Error/failure response class: 0b11 */ +//} +//tnet_stun_class_type_t; +// +///**@ingroup tnet_stun_group +// * List of all supported STUN methods. +// * RFC 5389 only define one method(Bining). All other methods have been defined +// * by TURN (draft-ietf-behave-turn-16 and draft-ietf-behave-turn-tcp-05). +//**/ +//typedef enum tnet_stun_method_type_e { +// stun_method_binding = 0x0001, /**< RFC 5389 - Binding method: 0b000000000001 */ +// +// stun_method_allocate = 0x0003, /**< draft-ietf-behave-turn-16 - Allocate (only request/response semantics defined) */ +// stun_method_refresh = 0x0004, /**< draft-ietf-behave-turn-16 - Refresh (only request/response semantics defined) */ +// stun_method_send = 0x0006, /**< draft-ietf-behave-turn-16 - Send (only indication semantics defined) */ +// stun_method_data = 0x0007, /**< draft-ietf-behave-turn-16 - Data (only indication semantics defined) */ +// stun_method_createpermission = 0x0008, /**< draft-ietf-behave-turn-16 - CreatePermission (only request/response semantics defined */ +// stun_method_channelbind = 0x0009, /**< draft-ietf-behave-turn-16 - ChannelBind (only request/response semantics defined) */ +//} +//tnet_stun_method_type_t; +// +///**@ingroup tnet_stun_group +//* List of all supported STUN types. +//*/ +//typedef enum tnet_stun_pkt_type_e { +// /* RFC 5389 - 6. STUN Message Structure +// +// The message type defines the message class (request, success +// response, failure response, or indication) and the message method +// (the primary function) of the STUN message. Although there are four +// message classes, there are only two types of transactions in STUN: +// request/response transactions (which consist of a request message and +// a response message) and indication transactions (which consist of a +// single indication message). Response classes are split into error +// and success responses to aid in quickly processing the STUN message. +// +// The message type field is decomposed further into the following +// structure: +// +// 0 1 +// 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +// +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ +// |M |M |M|M|M|C|M|M|M|C|M|M|M|M| +// |11|10|9|8|7|1|6|5|4|0|3|2|1|0| +// +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// stun_binding_request = (stun_method_binding | TNET_STUN_CLASS_REQUEST_MASK), +// stun_binding_indication = (stun_method_binding | TNET_STUN_CLASS_INDICATION_MASK), +// stun_binding_success_response = (stun_method_binding | TNET_STUN_CLASS_SUCCESS_MASK), +// stun_binding_error_response = (stun_method_binding | TNET_STUN_CLASS_ERROR_MASK), +// +// stun_allocate_request = (stun_method_allocate | TNET_STUN_CLASS_REQUEST_MASK), +// stun_allocate_indication = (stun_method_allocate | TNET_STUN_CLASS_INDICATION_MASK), +// stun_allocate_success_response = (stun_method_allocate | TNET_STUN_CLASS_SUCCESS_MASK), +// stun_allocate_error_response = (stun_method_allocate | TNET_STUN_CLASS_ERROR_MASK), +// +// stun_refresh_request = (stun_method_refresh | TNET_STUN_CLASS_REQUEST_MASK), +// stun_refresh_indication = (stun_method_refresh | TNET_STUN_CLASS_INDICATION_MASK), +// stun_refresh_success_response = (stun_method_refresh | TNET_STUN_CLASS_SUCCESS_MASK), +// stun_refresh_error_response = (stun_method_refresh | TNET_STUN_CLASS_ERROR_MASK), +// +// stun_send_indication = (stun_method_send | TNET_STUN_CLASS_INDICATION_MASK), +// +// stun_data_indication = (stun_method_data | TNET_STUN_CLASS_INDICATION_MASK), +// +// stun_createpermission_request = (stun_method_createpermission | TNET_STUN_CLASS_REQUEST_MASK), +// stun_createpermission_indication = (stun_method_createpermission | TNET_STUN_CLASS_INDICATION_MASK), +// stun_createpermission_success_response = (stun_method_createpermission | TNET_STUN_CLASS_SUCCESS_MASK), +// stun_createpermission_error_response = (stun_method_createpermission | TNET_STUN_CLASS_ERROR_MASK), +// +// stun_channelbind_request = (stun_method_channelbind | TNET_STUN_CLASS_REQUEST_MASK), +// stun_channelbind_indication = (stun_method_channelbind | TNET_STUN_CLASS_INDICATION_MASK), +// stun_channelbind_success_response = (stun_method_channelbind | TNET_STUN_CLASS_SUCCESS_MASK), +// stun_channelbind_error_response = (stun_method_channelbind | TNET_STUN_CLASS_ERROR_MASK), +//} +//tnet_stun_pkt_type_t; +// +///**@ingroup tnet_stun_group +// * +// * STUN Message structure as per RFC 5389 subclause 6. +// * http://tools.ietf.org/html/rfc5389#section-6 +//*/ +//typedef struct tnet_stun_pkt_s { +// TSK_DECLARE_OBJECT; +// +// /* +// 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) | +// | | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// */ +// +// tnet_stun_pkt_type_t type; +// uint16_t length; +// uint32_t cookie; +// tnet_stun_transac_id_t transaction_id; +// +// unsigned fingerprint:1; +// unsigned integrity:1; +// unsigned dontfrag:1; +// unsigned nointegrity:1; +// +// char* username; +// char* password; +// char* realm; +// char* nonce; +// +// tnet_stun_attributes_L_t *attributes; /**< List of all attributes associated to this message */ +//} +//tnet_stun_pkt_t; +// +//typedef tnet_stun_pkt_t tnet_stun_pkt_resp_t; +//typedef tnet_stun_pkt_t tnet_stun_pkt_req_t; +// +//TINYNET_API tsk_buffer_t* tnet_stun_pkt_serialize(const tnet_stun_pkt_t *message); +//tnet_stun_pkt_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size); +//tsk_bool_t tnet_stun_message_has_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type); +//TINYNET_API int tnet_stun_message_add_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_t** attribute); +//int tnet_stun_message_remove_attribute(tnet_stun_pkt_t *self, tnet_stun_attr_type_t type); +//const tnet_stun_attr_t* tnet_stun_message_get_attribute(const tnet_stun_pkt_t *self, tnet_stun_attr_type_t type); +//short tnet_stun_message_get_errorcode(const tnet_stun_pkt_t *self); +//const char* tnet_stun_message_get_realm(const tnet_stun_pkt_t *self); +//const char* tnet_stun_message_get_nonce(const tnet_stun_pkt_t *self); +//int32_t tnet_stun_message_get_lifetime(const tnet_stun_pkt_t *self); +//tsk_bool_t tnet_stun_utils_transac_id_equals(const tnet_stun_transac_id_t id1, const tnet_stun_transac_id_t id2); +// +// +//TINYNET_API tnet_stun_pkt_t* tnet_stun_message_create(const char* username, const char* password); +//TINYNET_API tnet_stun_pkt_t* tnet_stun_message_create_null(); +// +//TINYNET_GEXTERN const tsk_object_def_t *tnet_stun_message_def_t; +// +// +//TNET_END_DECLS +// +// +//#endif /* TNET_STUN_MESSAGE_H */ +// diff --git a/tinyNET/src/stun/tnet_stun_pkt.c b/tinyNET/src/stun/tnet_stun_pkt.c new file mode 100644 index 0000000..e4d559d --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_pkt.c @@ -0,0 +1,751 @@ +/* Copyright (C) 2015 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stun/tnet_stun_pkt.h" +#include "stun/tnet_stun_utils.h" + +#include "tnet_endianness.h" + +#include "tsk_sha1.h" +#include "tsk_hmac.h" +#include "tsk_md5.h" +#include "tsk_ppfcs32.h" +#include "tsk_buffer.h" +#include "tsk_string.h" +#include "tsk_memory.h" +#include "tsk_debug.h" + +#if !defined(PRINT_DESTROYED_MSG) +# define PRINT_DESTROYED_MSG 0 +#endif + +int tnet_stun_pkt_create(tnet_stun_pkt_type_t e_type, uint16_t u_length, const tnet_stun_transac_id_t* pc_transac_id, tnet_stun_pkt_t** pp_attr) +{ + extern const tsk_object_def_t *tnet_stun_pkt_def_t; + if (!pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!(*pp_attr = tsk_object_new(tnet_stun_pkt_def_t))) { + TSK_DEBUG_ERROR("Failed to create STUN pkt object"); + return -2; + } + if (!((*pp_attr)->p_list_attrs = tsk_list_create())) { + TSK_OBJECT_SAFE_FREE(*pp_attr); + return -3; + } + if (pc_transac_id) { + memcpy((*pp_attr)->transac_id, *pc_transac_id, sizeof(tnet_stun_transac_id_t)); + } + else { + tnet_stun_utils_transac_id_rand(&(*pp_attr)->transac_id); + } + (*pp_attr)->e_type = e_type; + (*pp_attr)->u_length = u_length; + return 0; +} + +int tnet_stun_pkt_attr_add(tnet_stun_pkt_t* p_self, tnet_stun_attr_t** pp_attr) +{ + if (!p_self || !pp_attr || !*pp_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + tsk_list_push_back_data(p_self->p_list_attrs, (void**)pp_attr); + return 0; +} + +int tnet_stun_pkt_attrs_add(tnet_stun_pkt_t* p_self, ...) +{ + va_list ap; + int ret = 0; + tnet_stun_pkt_attr_add_t e_add_attr; + if (!p_self) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + va_start(ap, p_self); + + while ((e_add_attr = va_arg(ap, tnet_stun_pkt_attr_add_t)) != tnet_stun_pkt_attr_add_null) { + switch (e_add_attr) { + case tnet_stun_pkt_attr_add_vdata: { + // (enum tnet_stun_attr_type_e)(E_TYPE), (const uint8_t*)(P_DATA_PTR), (uint16_t)(U_DATA_SIZE) + enum tnet_stun_attr_type_e E_TYPE = va_arg(ap, enum tnet_stun_attr_type_e); + const uint8_t* P_DATA_PTR = va_arg(ap, const uint8_t*); + uint16_t U_DATA_SIZE = tsk_va_arg_u16(ap); + tnet_stun_attr_vdata_t *p_attr; + if ((ret = tnet_stun_attr_vdata_create(E_TYPE, P_DATA_PTR, U_DATA_SIZE, &p_attr))) { + goto bail; + } + if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) { + TSK_OBJECT_SAFE_FREE(p_attr); + goto bail; + } + break; + } + case tnet_stun_pkt_attr_add_address: { + // (enum tnet_stun_attr_type_e)(E_TYPE), (enum tnet_stun_address_family_e)(E_FAMILY), (uint16_t)(U_PORT), (const tnet_stun_addr_t*)PC_ADDR_PTR + enum tnet_stun_attr_type_e E_TYPE = va_arg(ap, enum tnet_stun_attr_type_e); + enum tnet_stun_address_family_e E_FAMILY = va_arg(ap, enum tnet_stun_address_family_e); + uint16_t U_PORT = tsk_va_arg_u16(ap); + const tnet_stun_addr_t* PC_ADDR_PTR = va_arg(ap, const tnet_stun_addr_t*); + tnet_stun_attr_address_t *p_attr; + if ((ret = tnet_stun_attr_address_create(E_TYPE, E_FAMILY, U_PORT, PC_ADDR_PTR, &p_attr))) { + goto bail; + } + if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) { + TSK_OBJECT_SAFE_FREE(p_attr); + goto bail; + } + break; + } + case tnet_stun_pkt_attr_add_error_code: { + // (uint8_t)(U8_CLASS), (uint8_t)(U8_NUMBER), (const char*)(PC_REASON_STR) + uint8_t U8_CLASS = tsk_va_arg_u8(ap); + uint8_t U8_NUMBER = tsk_va_arg_u8(ap); + const char* PC_REASON_STR = va_arg(ap, const char*); + tnet_stun_attr_error_code_t *p_attr; + if ((ret = tnet_stun_attr_error_code_create(U8_CLASS, U8_NUMBER, PC_REASON_STR, (uint16_t)tsk_strlen(PC_REASON_STR), &p_attr))) { + goto bail; + } + if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) { + TSK_OBJECT_SAFE_FREE(p_attr); + goto bail; + } + break; + } + case tnet_stun_pkt_attr_add_unknown_attrs: { + // (...) + tsk_buffer_t* p_buffer = tsk_buffer_create_null(); + tnet_stun_attr_vdata_t *p_attr; + uint16_t u_16; + if (!p_buffer) { + TSK_DEBUG_ERROR("Failed to create buffer"); + ret = -4; + goto bail; + } + while ((e_add_attr = va_arg(ap, tnet_stun_pkt_attr_add_t)) != tnet_stun_pkt_attr_add_null) { + if (e_add_attr != tnet_stun_pkt_attr_add_unknown_attrs_val) { + TSK_OBJECT_SAFE_FREE(p_buffer); + TSK_DEBUG_ERROR("Arguments corrupted or invalid."); + ret = -3; + goto bail; + } + u_16 = tsk_va_arg_u16(ap); + tsk_buffer_append(p_buffer, &u_16, 2); + } + if ((ret = tnet_stun_attr_vdata_create(tnet_stun_attr_type_unknown_attrs, p_buffer->data, (uint16_t)p_buffer->size, &p_attr))) { + TSK_OBJECT_SAFE_FREE(p_buffer); + goto bail; + } + TSK_OBJECT_SAFE_FREE(p_buffer); + if ((ret = tnet_stun_pkt_attr_add(p_self, (tnet_stun_attr_t**)&p_attr))) { + TSK_OBJECT_SAFE_FREE(p_attr); + goto bail; + } + break; + } + default: { + TSK_DEBUG_ERROR("Arguments corrupted or invalid."); + ret = -2; + goto bail; + } + } + } + +bail: + va_end(ap); + return ret; +} + +int tnet_stun_pkt_attr_remove(struct tnet_stun_pkt_s* p_self, enum tnet_stun_attr_type_e e_type) +{ + tsk_list_item_t* pc_item; + tnet_stun_attr_t* pc_attr; + if (!p_self || !p_self->p_list_attrs) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + +again: + tsk_list_foreach(pc_item, p_self->p_list_attrs) { + if ((pc_attr = (tnet_stun_attr_t*)pc_item->data)) { + if (pc_attr->hdr.e_type == e_type) { + tsk_list_remove_item(p_self->p_list_attrs, pc_item); + goto again; + } + } + } + return 0; +} + +int tnet_stun_pkt_attr_find(const tnet_stun_pkt_t* pc_self, tnet_stun_attr_type_t e_type, tsk_size_t u_index, const tnet_stun_attr_t** ppc_attr) +{ + const tsk_list_item_t* pc_item; + const tnet_stun_attr_t* pc_attr; + if (!pc_self || !ppc_attr) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *ppc_attr = tsk_null; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) { + if (pc_attr->hdr.e_type == e_type && !u_index--) { + *ppc_attr = pc_attr; + break; + } + } + } + return 0; +} + +tsk_bool_t tnet_stun_pkt_attr_exists(const tnet_stun_pkt_t* pc_self, tnet_stun_attr_type_t e_type) +{ + const tnet_stun_attr_t* pc_attr; + int ret = tnet_stun_pkt_attr_find(pc_self, e_type, 0, &pc_attr); + return (pc_attr && (ret == 0)); +} + +int tnet_stun_pkt_get_size_in_octetunits_without_padding(const tnet_stun_pkt_t* pc_self, tsk_size_t* p_size) +{ + const tsk_list_item_t* pc_item; + const tnet_stun_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *p_size = kStunPktHdrSizeInOctets; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) { + if ((ret = tnet_stun_attr_get_size_in_octetunits_without_padding(pc_attr, &n_size))) { + return ret; + } + *p_size += n_size; + } + } + if (pc_self->opt.fingerprint) { + *p_size += kStunAttrHdrSizeInOctets + 4; + } + if (pc_self->opt.dontfrag) { + *p_size += kStunAttrHdrSizeInOctets; + } + return 0; +} + +int tnet_stun_pkt_get_size_in_octetunits_with_padding(const tnet_stun_pkt_t* pc_self, tsk_size_t* p_size) +{ + const tsk_list_item_t* pc_item; + const tnet_stun_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + if (!pc_self || !p_size) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *p_size = kStunPktHdrSizeInOctets; + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) { + if ((ret = tnet_stun_attr_get_size_in_octetunits_with_padding(pc_attr, &n_size))) { + return ret; + } + *p_size += n_size; + } + } + if (pc_self->opt.fingerprint) { + *p_size += kStunAttrHdrSizeInOctets + 4; + } + if (pc_self->opt.dontfrag) { + *p_size += kStunAttrHdrSizeInOctets; + } + return 0; +} + +int tnet_stun_pkt_write_with_padding(const tnet_stun_pkt_t* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written) +{ + const tsk_list_item_t* pc_item; + const tnet_stun_attr_t* pc_attr; + tsk_size_t n_size; + int ret; + uint8_t *_p_buff_ptr = p_buff_ptr, *_p_msg_int_start; + if (!pc_self || !p_buff_ptr || !n_buff_size || !p_written) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_self, p_written))) { + return ret; + } + if ((n_buff_size < *p_written)) { + TSK_DEBUG_ERROR("Buffer too short: %u<%u", (unsigned)n_buff_size, (unsigned)*p_written); + return -1; + } + + // write header + *((uint16_t*)&p_buff_ptr[0]) = tnet_htons((unsigned short)pc_self->e_type); + *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(kStunMagicCookie); + memcpy(&p_buff_ptr[8], pc_self->transac_id, sizeof(pc_self->transac_id)); + + p_buff_ptr += kStunPktHdrSizeInOctets; + n_buff_size -= kStunPktHdrSizeInOctets; + + // write attributes + tsk_list_foreach(pc_item, pc_self->p_list_attrs) { + if ((pc_attr = (const tnet_stun_attr_t*)pc_item->data)) { + if ((pc_attr->hdr.e_type == tnet_stun_attr_type_message_integrity)) { + continue; // because 'MESSAGE-INTEGRITY' must be the latest attribute + } + if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, p_buff_ptr, n_buff_size, &n_size))) { + return ret; + } + p_buff_ptr += n_size; + n_buff_size -= n_size; + } + } + + // DONT-FRAGMENT + if (pc_self->opt.dontfrag && tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_dont_fragment, &pc_attr) == 0 && !pc_attr) { + *((uint16_t*)&p_buff_ptr[0]) = tnet_htons(tnet_stun_attr_type_dont_fragment); // Type + *((uint16_t*)&p_buff_ptr[2]) = 0; // Length + p_buff_ptr += 4; + } + + // MESSAGE-INTEGRITY + if (!tsk_strnullORempty(pc_self->p_pwd) && tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_message_integrity, &pc_attr) == 0 && pc_attr) { + /* 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; + const tnet_stun_attr_vdata_t *pc_attr_username = tsk_null, *pc_attr_realm = tsk_null, *pc_attr_nonce = tsk_null; + static const uint16_t kMsgIntTotalLength = kStunAttrHdrSizeInOctets + TSK_SHA1_DIGEST_SIZE; + _p_msg_int_start = p_buff_ptr; + + // write attribute + if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, p_buff_ptr, n_buff_size, &n_size))) { + return ret; + } + p_buff_ptr += n_size; + n_buff_size -= n_size; + + // Length (must be correct before computing message integrity) + *((uint16_t*)&_p_buff_ptr[2]) = tnet_htons((unsigned short)((p_buff_ptr - _p_buff_ptr) - kStunPktHdrSizeInOctets)); + + if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_username, (const tnet_stun_attr_t**)&pc_attr_username))) { + return ret; + } + if (pc_attr_username) { + if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr_realm))) { + return ret; + } + if (pc_attr_realm) { + if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr_nonce))) { + return ret; + } + } + } + if (pc_attr_username && pc_attr_realm && pc_attr_nonce) { + // LONG-TERM + char* p_keystr = tsk_null; + tsk_md5digest_t md5; + tsk_sprintf(&p_keystr, "%s:%s:%s", pc_attr_username->p_data_ptr, pc_attr_realm->p_data_ptr, pc_self->p_pwd); + TSK_MD5_DIGEST_CALC(p_keystr, (tsk_size_t)tsk_strlen(p_keystr), md5); + hmac_sha1digest_compute(_p_buff_ptr, (tsk_size_t)(_p_msg_int_start - _p_buff_ptr), (const char*)md5, TSK_MD5_DIGEST_SIZE, hmac); + TSK_FREE(p_keystr); + } + else { + // SHORT-TERM + hmac_sha1digest_compute(_p_buff_ptr, (tsk_size_t)(_p_msg_int_start - _p_buff_ptr), pc_self->p_pwd, (tsk_size_t)tsk_strlen(pc_self->p_pwd), hmac); + } + + // update MESSAGE-INTEGRITY attribute value + if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, hmac, TSK_SHA1_DIGEST_SIZE))) { + return ret; + } + if ((ret = tnet_stun_attr_write_with_padding(&pc_self->transac_id, pc_attr, _p_msg_int_start, kMsgIntTotalLength, &n_size))) { + return ret; + } + } + + // Length before computing FINGERPRINT + *((uint16_t*)&_p_buff_ptr[2]) = tnet_htons((unsigned short)((p_buff_ptr - _p_buff_ptr) - kStunPktHdrSizeInOctets + ((pc_self->opt.fingerprint && (p_buff_ptr - _p_buff_ptr) >= 8) ? 8 : 0))); + + if (pc_self->opt.fingerprint && (p_buff_ptr - _p_buff_ptr) >= 8) { + /* 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 u_fingerprint = tsk_pppfcs32(TSK_PPPINITFCS32, _p_buff_ptr, (int32_t)(p_buff_ptr - _p_buff_ptr)) ^ kStunFingerprintXorConst; + *((uint16_t*)&p_buff_ptr[0]) = tnet_htons(tnet_stun_attr_type_fingerprint); // Type + *((uint16_t*)&p_buff_ptr[2]) = tnet_htons(4); // Length + *((uint32_t*)&p_buff_ptr[4]) = (uint32_t)tnet_htonl(u_fingerprint); + p_buff_ptr += 8; + } + + *p_written = (tsk_size_t)(p_buff_ptr - _p_buff_ptr); + return 0; +} + +int tnet_stun_pkt_write_with_padding_2(const struct tnet_stun_pkt_s* pc_self, struct tsk_buffer_s** pp_buff) +{ + tsk_size_t u_buff_size; + int ret; + if (!pc_self || !pp_buff) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pp_buff = tsk_null; + if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_self, &u_buff_size))) { + goto bail; + } + u_buff_size += kStunBuffMinPad; + if (!(*pp_buff = tsk_buffer_create(tsk_null, u_buff_size))) { + goto bail; + } + if ((ret = tnet_stun_pkt_write_with_padding(pc_self, (*pp_buff)->data, (*pp_buff)->size, &(*pp_buff)->size))) { + goto bail; + } +bail: + if (ret) { + TSK_OBJECT_SAFE_FREE(*pp_buff); + } + return ret; +} + +int tnet_stun_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete) +{ + if (!pb_is_complete) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pb_is_complete = tsk_false; + if (pc_buff_ptr && n_buff_size >= kStunPktHdrSizeInOctets) { + tsk_size_t n_paylen_in_octets = tnet_ntohs_2(&pc_buff_ptr[2]); + *pb_is_complete = ((n_buff_size - kStunPktHdrSizeInOctets) >= n_paylen_in_octets); + } + return 0; +} + +int tnet_stun_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tnet_stun_pkt_t** pp_pkt) +{ + tsk_bool_t b_is_complete; + uint16_t PayloadLengthInOctets; + tnet_stun_pkt_type_t Type; + tnet_stun_transac_id_t transac_id; + uint32_t MagicCookie; + int ret; + + if (!pc_buff_ptr || !n_buff_size || !pp_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (!TNET_STUN_BUFF_IS_STUN2(pc_buff_ptr, n_buff_size)) { + TSK_DEBUG_ERROR("Buffer doesn't contain a valid STUN2 pkt"); + return -2; + } + if ((ret = tnet_stun_pkt_is_complete(pc_buff_ptr, n_buff_size, &b_is_complete))) { + return ret; + } + if (!b_is_complete) { + TSK_DEBUG_ERROR("Buffer too short(%u)", (unsigned)n_buff_size); + return -3; + } + + // read the header + Type = tnet_ntohs_2(&pc_buff_ptr[0]); + PayloadLengthInOctets = tnet_ntohs_2(&pc_buff_ptr[2]); + MagicCookie = (uint32_t)tnet_ntohl_2(&pc_buff_ptr[4]); + if (MagicCookie != kStunMagicCookieLong) { + TSK_DEBUG_ERROR("%x not a valid STUN2 magic cookie", MagicCookie); + return -4; + } + memcpy(transac_id, &pc_buff_ptr[8], sizeof(tnet_stun_transac_id_t)); + // create the pkt + if ((ret = tnet_stun_pkt_create(Type, PayloadLengthInOctets, (const tnet_stun_transac_id_t*)&transac_id, pp_pkt))) { + return ret; + } + + if (PayloadLengthInOctets > 0) { + tnet_stun_attr_t* p_attr; + tsk_size_t n_consumed_octets; + pc_buff_ptr += kStunPktHdrSizeInOctets; + do { + if ((ret = tnet_stun_attr_read((const tnet_stun_transac_id_t*)&(*pp_pkt)->transac_id, pc_buff_ptr, PayloadLengthInOctets, &n_consumed_octets, &p_attr))) { + return ret; + } + if ((ret = tnet_stun_pkt_attr_add((*pp_pkt), &p_attr))) { + TSK_OBJECT_SAFE_FREE((*pp_pkt)); + return ret; + } + PayloadLengthInOctets -= (uint16_t)n_consumed_octets; + pc_buff_ptr += n_consumed_octets; + } while (PayloadLengthInOctets >= kStunAttrHdrSizeInOctets); + } + + return 0; +} + +int tnet_stun_pkt_auth_prepare(tnet_stun_pkt_t* p_self, const char* pc_usr_name, const char* pc_pwd, const char* pc_realm, const char* pc_nonce) +{ + const tnet_stun_attr_t* pc_attr; + int ret; + static const tsk_sha1digest_t __pc_sha1digestEmpty = { 0 }; + static const uint16_t __u_sha1digestEmpty = sizeof(__pc_sha1digestEmpty); + if (!p_self /*|| !pc_usr_name*/ || !pc_pwd /*|| !pc_realm || !pc_nonce*/) { // "username", "realm" and "nonce" are null for short-term authentication + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + // USERNAME + if (pc_usr_name) { // LONG-TERM, optional for SHORT-TERM + if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_username, &pc_attr))) { + goto bail; + } + if (pc_attr) { + if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_usr_name, (uint16_t)tsk_strlen(pc_usr_name)))) { + goto bail; + } + } + else { + ret = tnet_stun_pkt_attrs_add(p_self, + TNET_STUN_PKT_ATTR_ADD_USERNAME_ZT(pc_usr_name), + TNET_STUN_PKT_ATTR_ADD_NULL()); + if (ret) { + goto bail; + } + } + } + // REALM + if (pc_realm) { // LONG-TERM + if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_realm, &pc_attr))) { + goto bail; + } + if (pc_attr) { + if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_realm, (uint16_t)tsk_strlen(pc_realm)))) { + goto bail; + } + } + else { + ret = tnet_stun_pkt_attrs_add(p_self, + TNET_STUN_PKT_ATTR_ADD_REALM_ZT(pc_realm), + TNET_STUN_PKT_ATTR_ADD_NULL()); + if (ret) { + goto bail; + } + } + } + // NONCE + if (pc_nonce) { // LONG-TERM + if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_nonce, &pc_attr))) { + goto bail; + } + if (pc_attr) { + if ((ret = tnet_stun_attr_vdata_update((tnet_stun_attr_vdata_t*)pc_attr, (const uint8_t*)pc_nonce, (uint16_t)tsk_strlen(pc_nonce)))) { + goto bail; + } + } + else { + ret = tnet_stun_pkt_attrs_add(p_self, + TNET_STUN_PKT_ATTR_ADD_NONCE_ZT(pc_nonce), + TNET_STUN_PKT_ATTR_ADD_NULL()); + if (ret) { + goto bail; + } + } + } + // MESSAGE-INTEGRITY + if ((ret = tnet_stun_pkt_attr_find_first(p_self, tnet_stun_attr_type_message_integrity, &pc_attr))) { + goto bail; + } + if (!pc_attr) { + ret = tnet_stun_pkt_attrs_add(p_self, + TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(__pc_sha1digestEmpty, __u_sha1digestEmpty), + TNET_STUN_PKT_ATTR_ADD_NULL()); + if (ret) { + goto bail; + } + } + + // PASSWORD + tsk_strupdate(&p_self->p_pwd, pc_pwd); + +bail: + return ret; +} + +// pc_resp = 401 or 438 +int tnet_stun_pkt_auth_prepare_2(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_resp) +{ + const tnet_stun_attr_vdata_t* pc_attr; + const char *pc_nonce, *pc_realm; + int ret; + if (!p_self || !pc_usr_name || !pc_pwd || !pc_resp) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + // NONCE + if ((ret = tnet_stun_pkt_attr_find_first(pc_resp, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr))) { + goto bail; + } + if (!pc_attr || !pc_attr->p_data_ptr || !pc_attr->u_data_size) { + TSK_DEBUG_ERROR("Invalid NONCE in 401"); + ret = -3; + goto bail; + } + pc_nonce = (const char*)pc_attr->p_data_ptr; + // REALM + if ((ret = tnet_stun_pkt_attr_find_first(pc_resp, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr))) { + goto bail; + } + if (!pc_attr || !pc_attr->p_data_ptr || !pc_attr->u_data_size) { + TSK_DEBUG_ERROR("Invalid REALM in 401"); + ret = -3; + goto bail; + } + pc_realm = (const char*)pc_attr->p_data_ptr; + + if ((ret = tnet_stun_pkt_auth_prepare(p_self, pc_usr_name, pc_pwd, pc_realm, pc_nonce))) { + goto bail; + } + + // TRANSACTION-ID + if ((ret = tnet_stun_utils_transac_id_rand(&p_self->transac_id))) { + goto bail; + } + +bail: + return ret; +} + +int tnet_stun_pkt_auth_copy(tnet_stun_pkt_t* p_self, const char* pc_usr_name, const char* pc_pwd, const tnet_stun_pkt_t* pc_pkt) +{ + const tnet_stun_attr_vdata_t *pc_attr_realm = tsk_null, *pc_attr_nonce = tsk_null; + int ret; + tsk_bool_t b_ok; + if (!p_self || !pc_pwd || !pc_usr_name || !pc_pkt) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + + b_ok = + (ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_realm, (const tnet_stun_attr_t**)&pc_attr_realm)) == 0 && pc_attr_realm + && (ret = tnet_stun_pkt_attr_find_first(pc_pkt, tnet_stun_attr_type_nonce, (const tnet_stun_attr_t**)&pc_attr_nonce)) == 0 && pc_attr_nonce; + + if (b_ok && (ret = tnet_stun_pkt_auth_prepare(p_self, pc_usr_name, pc_pwd, (const char*)pc_attr_realm->p_data_ptr, (const char*)pc_attr_nonce->p_data_ptr))) { + goto bail; + } + +bail: + return ret; +} + +int tnet_stun_pkt_get_errorcode(const struct tnet_stun_pkt_s* pc_self, uint16_t* pu_code) +{ + const tnet_stun_attr_error_code_t* pc_attr; + int ret; + if (!pc_self && !pu_code) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + *pu_code = 0; + if ((ret = tnet_stun_pkt_attr_find_first(pc_self, tnet_stun_attr_type_error_code, (const tnet_stun_attr_t**)&pc_attr))) { + return ret; + } + if (pc_attr) { + *pu_code = (pc_attr->u_class * 100) + pc_attr->u_number; + } + return 0; +} + +int tnet_stun_pkt_process_err420(struct tnet_stun_pkt_s *p_self, const struct tnet_stun_pkt_s *pc_pkt_resp420) +{ + const tnet_stun_attr_vdata_t* pc_attr; + uint16_t u16; + int ret; + tsk_bool_t b_done = tsk_false; + if (!p_self || !pc_pkt_resp420) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tnet_stun_pkt_attr_find_first(pc_pkt_resp420, tnet_stun_attr_type_unknown_attrs, (const tnet_stun_attr_t**)&pc_attr))) { + goto bail; + } + if (!pc_attr || !pc_attr->p_data_ptr || (pc_attr->u_data_size & 1)) { + TSK_DEBUG_ERROR("UNKNOWN-ATTRIBUTES missing in 420"); + ret = -3; + goto bail; + } + for (u16 = 0; u16 < pc_attr->u_data_size; u16 += 2) { + switch (*((uint16_t*)&pc_attr->p_data_ptr[u16])) { + case tnet_stun_attr_type_dont_fragment: { + p_self->opt.dontfrag = 0; + b_done = tsk_true; + break; + } + case tnet_stun_attr_type_fingerprint: { + p_self->opt.fingerprint = 0; + b_done = tsk_true; + break; + } + } + } + + if (b_done) { + // TRANSACTION-ID + if ((ret = tnet_stun_utils_transac_id_rand(&p_self->transac_id))) { + goto bail; + } + } + +bail: + return ret; +} + +static tsk_object_t* tnet_stun_pkt_ctor(tsk_object_t * self, va_list * app) +{ + tnet_stun_pkt_t *p_pkt = (tnet_stun_pkt_t *)self; + if (p_pkt) { + p_pkt->opt.fingerprint = kStunOptFingerPrint; + p_pkt->opt.dontfrag = kStunOptDontFragment; + } + return self; +} +static tsk_object_t* tnet_stun_pkt_dtor(tsk_object_t * self) +{ + tnet_stun_pkt_t *p_pkt = (tnet_stun_pkt_t *)self; + if (p_pkt) { +#if PRINT_DESTROYED_MSG + TSK_DEBUG_INFO("*** STUN pkt destroyed ***"); +#endif + TSK_OBJECT_SAFE_FREE(p_pkt->p_list_attrs); + TSK_FREE(p_pkt->p_pwd); + } + return self; +} +static const tsk_object_def_t tnet_stun_pkt_def_s = { + sizeof(tnet_stun_pkt_t), + tnet_stun_pkt_ctor, + tnet_stun_pkt_dtor, + tsk_null, +}; +const tsk_object_def_t *tnet_stun_pkt_def_t = &tnet_stun_pkt_def_s; diff --git a/tinyNET/src/stun/tnet_stun_pkt.h b/tinyNET/src/stun/tnet_stun_pkt.h new file mode 100644 index 0000000..da27673 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_pkt.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TNET_STUN_PKT_H +#define TNET_STUN_PKT_H + +#include "tinynet_config.h" +#include "stun/tnet_stun_attr.h" + +#include "tsk_object.h" +#include "tsk_list.h" +#include "tsk_buffer.h" + +TNET_BEGIN_DECLS + + +/**@ingroup tnet_stun_group +* @def TNET_STUN_PKT_IS_REQ +* Checks whether the STUN message is a request or not. +*/ +/**@ingroup tnet_stun_group +* @def TNET_STUN_PKT_IS_INDICATION +* Checks whether the STUN message is an indicaton message or not. +*/ +/**@ingroup tnet_stun_group +* @def TNET_STUN_RESP_IS_SUCCESS +* Checks whether the STUN message is a success response or not. +*/ +/**@ingroup tnet_stun_group +* @def TNET_STUN_RESP_IS_ERROR +* Checks whether the STUN message is an error response or not. +*/ +#define TNET_STUN_PKT_IS_REQ(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_request)) +#define TNET_STUN_PKT_IS_RESP(p_self) (TNET_STUN_PKT_RESP_IS_SUCCESS((p_self)) || TNET_STUN_PKT_RESP_IS_ERROR((p_self))) +#define TNET_STUN_PKT_IS_INDICATION(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_indication)) +#define TNET_STUN_PKT_RESP_IS_SUCCESS(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_success)) +#define TNET_STUN_PKT_RESP_IS_ERROR(p_self) ((p_self) && (((p_self)->e_type & 0x0110) == tnet_stun_mask_error)) + +typedef enum tnet_stun_pkt_attr_add_e { + tnet_stun_pkt_attr_add_null = 0, + tnet_stun_pkt_attr_add_none = tnet_stun_pkt_attr_add_null, + tnet_stun_pkt_attr_add_vdata, + tnet_stun_pkt_attr_add_address, + tnet_stun_pkt_attr_add_error_code, + tnet_stun_pkt_attr_add_unknown_attrs, + tnet_stun_pkt_attr_add_unknown_attrs_val, +} +tnet_stun_pkt_attr_add_t; + +#define TNET_STUN_PKT_ATTR_ADD_NULL() tnet_stun_pkt_attr_add_null +#define TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, P_DATA_PTR, U_DATA_SIZE) tnet_stun_pkt_attr_add_vdata, (enum tnet_stun_attr_type_e)(E_TYPE), (const uint8_t*)(P_DATA_PTR), (uint16_t)(U_DATA_SIZE) +#define TNET_STUN_PKT_ATTR_ADD_UINT0(E_TYPE) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, tsk_null, 0) +#define TNET_STUN_PKT_ATTR_ADD_UINT8(E_TYPE, U8) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U8, 1) +#define TNET_STUN_PKT_ATTR_ADD_UINT16(E_TYPE, U16) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U16, 2) +#define TNET_STUN_PKT_ATTR_ADD_UINT32(E_TYPE, U32) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U32, 4) +#define TNET_STUN_PKT_ATTR_ADD_UINT64(E_TYPE, U64) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, &U64, 8) +#define TNET_STUN_PKT_ATTR_ADD_STR(E_TYPE, PC_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(E_TYPE, PC_STR, tsk_strlen(PC_STR)) +#define TNET_STUN_PKT_ATTR_ADD_ADDRESS(E_TYPE, E_FAMILY, U_PORT, PC_ADDR_PTR) tnet_stun_pkt_attr_add_address, (enum tnet_stun_attr_type_e)(E_TYPE), (enum tnet_stun_address_family_e)(E_FAMILY), (uint16_t)(U_PORT), (const tnet_stun_addr_t*)PC_ADDR_PTR +#define TNET_STUN_PKT_ATTR_ADD_ADDRESS_V4(E_TYPE, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS((E_TYPE), tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_ADDRESS_V6(E_TYPE, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS((E_TYPE), tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR)) +// rfc5389 - 15.1. MAPPED-ADDRESS +#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_mapped_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_MAPPED_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR)) +// rfc5389 - 15.2. XOR-MAPPED-ADDRESS +#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_xor_mapped_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_MAPPED_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR)) +// rfc5389 - 15.3. USERNAME +#define TNET_STUN_PKT_ATTR_ADD_USERNAME(PC_USERNAME_STR, U_USERNAME_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_username, (PC_USERNAME_STR), (U_USERNAME_STR)) +#define TNET_STUN_PKT_ATTR_ADD_USERNAME_ZT(PC_USERNAME_STR) TNET_STUN_PKT_ATTR_ADD_USERNAME(PC_USERNAME_STR, tsk_strlen(PC_USERNAME_STR)) +// rfc5389 - 15.4. MESSAGE-INTEGRITY +#define TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(PC_SHA1_STR, U_SHA1_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_message_integrity, (PC_SHA1_STR), (U_SHA1_STR)) +#define TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY_ZT(PC_SHA1_STR) TNET_STUN_PKT_ATTR_ADD_MESSAGE_INTEGRITY(PC_SHA1_STR, tsk_strlen(PC_SHA1_STR)) +// rfc5389 - 15.5. FINGERPRINT +#define TNET_STUN_PKT_ATTR_ADD_FINGERPRINT(U32_CRC32) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_fingerprint, U32_CRC32) +// rfc5389 - 15.6. ERROR-CODE +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(U8_CLASS, U8_NUMBER, PC_REASON_STR) tnet_stun_pkt_attr_add_error_code, (uint8_t)(U8_CLASS), (uint8_t)(U8_NUMBER), (const char*)(PC_REASON_STR) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_TRY_ALTERNATE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassTryAlternate, kStunErrorNumberTryAlternate, kStunErrorPhraseTryAlternate) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_BAD_REQUEST() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassBadRequest, kStunErrorNumberBadRequest, kStunErrorPhraseBadRequest) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNAUTHORIZED() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassUnauthorized, kStunErrorNumberUnauthorized, kStunErrorPhraseUnauthorized) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_UNKNOWN_ATTRIBUTE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassUnknownAttribute, kStunErrorNumberUnknownAttribute, kStunErrorPhraseUnknownAttribute) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_STALE_NONCE() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassStaleNonce, kStunErrorNumberStaleNonce, kStunErrorPhraseStaleNonce) +#define TNET_STUN_PKT_ATTR_ADD_ERROR_CODE_SERVER_ERROR() TNET_STUN_PKT_ATTR_ADD_ERROR_CODE(kStunErrorClassServerError, kStunErrorNumberServerError, kStunErrorPhraseServerError) +// rfc5389 - 15.7. REALM +#define TNET_STUN_PKT_ATTR_ADD_REALM(PC_REALM_STR, U_REALM_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_realm, (PC_REALM_STR), (U_REALM_STR)) +#define TNET_STUN_PKT_ATTR_ADD_REALM_ZT(PC_REALM_STR) TNET_STUN_PKT_ATTR_ADD_REALM(PC_REALM_STR, tsk_strlen(PC_REALM_STR)) +// rfc5389 - 15.8. NONCE +#define TNET_STUN_PKT_ATTR_ADD_NONCE(PC_NONCE_STR, U_NONCE_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_nonce, (PC_NONCE_STR), (U_NONCE_STR)) +#define TNET_STUN_PKT_ATTR_ADD_NONCE_ZT(PC_NONCE_STR) TNET_STUN_PKT_ATTR_ADD_NONCE(PC_NONCE_STR, tsk_strlen(PC_NONCE_STR)) +// rfc5389 - 15.9. UNKNOWN-ATTRIBUTES +#define TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS(...) tnet_stun_pkt_attr_add_unknown_attrs, ##__VA_ARGS__ +#define TNET_STUN_PKT_ATTR_ADD_UNKNOWN_ATTRS_VAL(U16_VAL) tnet_stun_pkt_attr_add_unknown_attrs_val, (uint16_t)U16_VAL +// rfc5389 - 15.10. SOFTWARE +#define TNET_STUN_PKT_ATTR_ADD_SOFTWARE(PC_SOFTWARE_STR, U_SOFTWARE_STR) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_software, (PC_SOFTWARE_STR), (U_SOFTWARE_STR)) +#define TNET_STUN_PKT_ATTR_ADD_SOFTWARE_ZT(PC_SOFTWARE_STR) TNET_STUN_PKT_ATTR_ADD_SOFTWARE(PC_SOFTWARE_STR, tsk_strlen(PC_SOFTWARE_STR)) +// rfc5389 - 15.11. ALTERNATE-SERVER +#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_alternate_server, (E_FAMILY), (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ALTERNATE_SERVER(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR)) + +// rfc5766(TURN) - 14.1. CHANNEL-NUMBER +#define TNET_STUN_PKT_ATTR_ADD_CHANNEL_NUMBER(U16_CHANNEL_NUMBER) TNET_STUN_PKT_ATTR_ADD_UINT16(tnet_stun_attr_type_channel_number, U16_CHANNEL_NUMBER) +// rfc5766(TURN) - 14.2. LIFETIME +#define TNET_STUN_PKT_ATTR_ADD_LIFETIME(U32_LIFETIME) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_lifetime, U32_LIFETIME) +// rfc5766(TURN) - 14.3. XOR-PEER-ADDRESS +#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(E_FAMILY, U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_ADDRESS(tnet_stun_attr_type_xor_peer_address, (E_FAMILY), (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS_V4(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(tnet_stun_address_family_ipv4, (U_PORT), (PC_ADDR_PTR)) +#define TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS_V6(U_PORT, PC_ADDR_PTR) TNET_STUN_PKT_ATTR_ADD_XOR_PEER_ADDRESS(tnet_stun_address_family_ipv6, (U_PORT), (PC_ADDR_PTR)) +// rfc5766(TURN) - 14.4. DATA +#define TNET_STUN_PKT_ATTR_ADD_DATA(PC_DATA_PTR, U_DATA_SIZE) TNET_STUN_PKT_ATTR_ADD_VDATA(tnet_stun_attr_type_data, (PC_DATA_PTR), (U_DATA_SIZE)) +// rfc5766(TURN) - 14.7. REQUESTED-TRANSPORT +#define TNET_STUN_PKT_ATTR_ADD_REQUESTED_TRANSPORT(U8_PROTOCOL) TNET_STUN_PKT_ATTR_ADD_UINT8(tnet_stun_attr_type_requested_transport, U8_PROTOCOL) +// rfc5766(TURN) - 14.8. DONT-FRAGMENT +#define TNET_STUN_PKT_ATTR_ADD_DONT_FRAGMENT() TNET_STUN_PKT_ATTR_ADD_UINT0(tnet_stun_attr_type_dont_fragment) + +// rfc5245(ICE) - 19.1. New Attributes (PRIORITY) +#define TNET_STUN_PKT_ATTR_ADD_ICE_PRIORITY(U32_PRIORITY) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_ice_priority, U32_PRIORITY) +// rfc5245(ICE) - 19.1. New Attributes (USE-CANDIDATE) +#define TNET_STUN_PKT_ATTR_ADD_ICE_USE_CANDIDATE() TNET_STUN_PKT_ATTR_ADD_UINT0(tnet_stun_attr_type_ice_use_candidate) +// rfc5245(ICE) - 19.1. New Attributes (ICE-CONTROLLED) +#define TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLED(U64_CONTROLLED) TNET_STUN_PKT_ATTR_ADD_UINT64(tnet_stun_attr_type_ice_controlled, U64_CONTROLLED) +// rfc5245(ICE) - 19.1. New Attributes (ICE-CONTROLLED) +#define TNET_STUN_PKT_ATTR_ADD_ICE_CONTROLLING(U64_CONTROLLING) TNET_STUN_PKT_ATTR_ADD_UINT64(tnet_stun_attr_type_ice_controlling, U64_CONTROLLING) + +// rfc6062 - 6.2. New STUN Attributes (CONNECTION-ID) +#define TNET_STUN_PKT_ATTR_ADD_CONNECTION_ID(U32_CONNECTION_ID) TNET_STUN_PKT_ATTR_ADD_UINT32(tnet_stun_attr_type_connection_id, U32_CONNECTION_ID) + +typedef struct tnet_stun_pkt_s { + TSK_DECLARE_OBJECT; + enum tnet_stun_pkt_type_e e_type; + uint16_t u_length; // 16bits: contain the size, in bytes, of the message not including the 20-byte STUN header + tnet_stun_transac_id_t transac_id; // 96bits : always in network byte-order + tnet_stun_attrs_L_t* p_list_attrs; + struct { + unsigned fingerprint:1; + unsigned dontfrag:1; + } opt; + char *p_pwd; +} tnet_stun_pkt_t; +#define TNET_STUN_DECLARE_PKT struct tnet_stun_pkt_s __base__ +#define TNET_STUN_PKT(p_self) ((struct tnet_stun_pkt_s*)(p_self)) +typedef tsk_list_t tnet_stun_pkts_L_t; +typedef tnet_stun_pkt_t tnet_stun_pkt_req_t; +typedef tnet_stun_pkt_t tnet_stun_pkt_resp_t; + +TINYNET_API int tnet_stun_pkt_create(enum tnet_stun_pkt_type_e e_type, uint16_t u_length, const tnet_stun_transac_id_t* pc_transac_id, struct tnet_stun_pkt_s** pp_attr); +#define tnet_stun_pkt_create_empty(e_type, pp_attr) tnet_stun_pkt_create((e_type), 0, tsk_null, (pp_attr)) +TINYNET_API int tnet_stun_pkt_attr_add(struct tnet_stun_pkt_s* p_self, struct tnet_stun_attr_s** pp_attr); +TINYNET_API int tnet_stun_pkt_attrs_add(struct tnet_stun_pkt_s* p_self, ...); +TINYNET_API int tnet_stun_pkt_attr_remove(struct tnet_stun_pkt_s* p_self, enum tnet_stun_attr_type_e e_type); +TINYNET_API int tnet_stun_pkt_attr_find(const struct tnet_stun_pkt_s* pc_self, enum tnet_stun_attr_type_e e_type, tsk_size_t u_index, const struct tnet_stun_attr_s** ppc_attr); +#define tnet_stun_pkt_attr_find_first(pc_self, e_type, ppc_attr) tnet_stun_pkt_attr_find((pc_self), (e_type), 0, (ppc_attr)) +TINYNET_API tsk_bool_t tnet_stun_pkt_attr_exists(const struct tnet_stun_pkt_s* pc_self, enum tnet_stun_attr_type_e e_type); +TINYNET_API int tnet_stun_pkt_get_size_in_octetunits_without_padding(const struct tnet_stun_pkt_s* pc_self, tsk_size_t* p_size); +TINYNET_API int tnet_stun_pkt_get_size_in_octetunits_with_padding(const struct tnet_stun_pkt_s* pc_self, tsk_size_t* p_size); +TINYNET_API int tnet_stun_pkt_write_with_padding(const struct tnet_stun_pkt_s* pc_self, uint8_t* p_buff_ptr, tsk_size_t n_buff_size, tsk_size_t *p_written); +TINYNET_API int tnet_stun_pkt_write_with_padding_2(const struct tnet_stun_pkt_s* pc_self, struct tsk_buffer_s** pp_buff); +TINYNET_API int tnet_stun_pkt_is_complete(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, tsk_bool_t *pb_is_complete); +TINYNET_API int tnet_stun_pkt_read(const uint8_t* pc_buff_ptr, tsk_size_t n_buff_size, struct tnet_stun_pkt_s** pp_pkt); +TINYNET_API int tnet_stun_pkt_auth_prepare(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const char* pc_realm, const char* pc_nonce); +#define tnet_stun_pkt_auth_prepare_longterm(p_self, pc_usr_name, pc_pwd, pc_realm, pc_nonce) tnet_stun_pkt_auth_prepare((p_self), (pc_usr_name), (pc_pwd), (pc_realm), (pc_nonce)) +#define tnet_stun_pkt_auth_prepare_shortterm(p_self, pc_usr_name, pc_pwd) tnet_stun_pkt_auth_prepare((p_self), (pc_usr_name), (pc_pwd), tsk_null, tsk_null) +#define tnet_stun_pkt_auth_prepare_shortterm_2(p_self, pc_pwd) tnet_stun_pkt_auth_prepare_shortterm((p_self), tsk_null, (pc_pwd)) +TINYNET_API int tnet_stun_pkt_auth_prepare_2(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_resp); +TINYNET_API int tnet_stun_pkt_auth_copy(struct tnet_stun_pkt_s* p_self, const char* pc_usr_name, const char* pc_pwd, const struct tnet_stun_pkt_s* pc_pkt); +TINYNET_API int tnet_stun_pkt_get_errorcode(const struct tnet_stun_pkt_s* pc_self, uint16_t* pu_code); +TINYNET_API int tnet_stun_pkt_process_err420(struct tnet_stun_pkt_s *p_self, const struct tnet_stun_pkt_s *pc_pkt_resp420); + +TNET_END_DECLS + +#endif /* TNET_STUN_PKT_H */ diff --git a/tinyNET/src/stun/tnet_stun_types.h b/tinyNET/src/stun/tnet_stun_types.h new file mode 100644 index 0000000..386f471 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_types.h @@ -0,0 +1,373 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TNET_STUN_TYPES_H +#define TNET_STUN_TYPES_H + +#include "tinynet_config.h" + +TNET_BEGIN_DECLS + +typedef uint8_t tnet_stun_addr_t[16]; // IPv4(32bits) or IPv6(128bits) +typedef uint64_t tnet_stun_binding_id_t; +typedef long tnet_turn_peer_id_t; + +/**@ingroup tnet_stun_group + * Checks if the pointer to the buffer hold a STUN header by checking that it starts with 0b00 and contain the magic cookie. + * As per RFC 5389 subclause 19: Explicitly point out that the most significant 2 bits of STUN are + * 0b00, allowing easy differentiation with RTP packets when used with ICE. + * As per RFC 5389 subclause 6: The magic cookie field MUST contain the fixed value 0x2112A442 in + * network byte order. + * + * @param PU8 The pointer to the buffer holding the STUN raw data. +**/ +#define TNET_STUN_BUFF_IS_STUN2(PU8, SIZE) \ + ( \ + ((PU8)) && \ + ((SIZE) >= kStunPktHdrSizeInOctets) && \ + (((PU8)[0] & 0xc0) == 0x00) && \ + ( PU8[4] == 0x21 && PU8[5] == 0x12 && PU8[6] == 0xA4 && PU8[7] == 0x42 ) \ + ) + +// rfc5766 - 11. Channels +#define TNET_STUN_BUFF_IS_CHANNEL_DATA(PU8, SIZE) \ + ( \ + ((PU8)) && \ + ((SIZE) >= kStunChannelDataHdrSizeInOctets) && \ + (((PU8)[0] & 0xc0) == 0x40) \ + ) + +#define kStunOptFingerPrint 1 +#define kStunOptDontFragment 1 + +#define kStunErrCodeUnauthorized 401 +#define kStunErrCodeUnknownAttributes 420 +#define kStunErrCodeStaleNonce 438 +#define kStunErrCodeIceConflict 487 + +// Estimate of the round-trip time (RTT) in millisecond. +#define kStunRTO 500 + +// Number of retransmission for UDP retransmission in millisecond. +// 7.2.1. Sending over UDP +// Rc SHOULD be configurable and SHOULD have a default of 7. +#define kStunRC /*7*/4/* 7 is too hight */ + +#define kStunBindingInvalidId 0 + +#if !defined(kStunBuffMinPad) +# define kStunBuffMinPad 40 // to make the buffer kasher +#endif /* kStunBuffMinPad */ + +#if !defined(kStunSoftware) +# define kStunSoftware TNET_SOFTWARE +#endif /* kStunSoftware */ + +#if !defined(kStunPortDefaultTcpUdp) +# define kStunPortDefaultTcpUdp 3478 +#endif /* kStunPortDefaultTcpUdp */ + +#if !defined(kStunPortDefaultTls) +# define kStunPortDefaultTls 5349 +#endif /* kStunPortDefaultTls */ + +// rfc5389 - 15. STUN Attributes +#if !defined(kStunAttrHdrSizeInOctets) +# define kStunAttrHdrSizeInOctets 4 +#endif /* kStunAttrHdrSizeInOctets */ + +// rfc5389 - 6. STUN Message Structure +#if !defined(kStunPktHdrSizeInOctets) +# define kStunPktHdrSizeInOctets 20 +#endif /* kStunPktHdrSizeInOctets */ + +// STUN2 magic cookie value in network byte order as per RFC 5389 subclause 6. +#if !defined(kStunMagicCookieLong) +# define kStunMagicCookieLong 0x2112A442 +#endif /* kStunMagicCookieLong */ +#if !defined(kStunMagicCookie) +# define kStunMagicCookie kStunMagicCookieLong +#endif /* kStunMagicCookie */ +#if !defined(kStunMagicCookieShort) +# define kStunMagicCookieShort 0x2112 +#endif /* kStunMagicCookieShort */ + +#if !defined (kStunFingerprintXorConst) +# define kStunFingerprintXorConst 0x5354554e +#endif /* kStunFingerprintXorConst */ + +// STUN trasactionn ID size (96bits = 12bytes) +#if !defined(kStunTransacIdSize) +# define kStunTransacIdSize 12 +#endif +typedef uint8_t tnet_stun_transac_id_t[kStunTransacIdSize]; + +/**@ingroup tnet_stun_group + * List of all supported STUN classes as per RFC 5389 subcaluse 6. +**/ +typedef enum tnet_stun_class_e { + tnet_stun_class_request = 0x00, /**< Request class: 0b00 */ + tnet_stun_class_indication = 0x01, /**< Indication class: 0b01 */ + tnet_stun_class_success_response = 0x02, /**< Success response class: 0b10 */ + tnet_stun_class_error_response = 0x03, /**< Error/failure response class: 0b11 */ +} +tnet_stun_class_t; + +/**@ingroup tnet_stun_group + * List of all supported STUN methods. + * RFC 5389 defines only one method(Bining). All other methods have been defined by TURN (rfc5766 section 13). +**/ +typedef enum tnet_stun_method_e { + tnet_stun_method_binding = 0x0001, /**< RFC 5389 - Binding method: 0b000000000001 */ + + tnet_stun_method_allocate = 0x0003, /**< rfc5766 - Allocate (only request/response semantics defined) */ + tnet_stun_method_refresh = 0x0004, /**< rfc5766 - Refresh (only request/response semantics defined) */ + tnet_stun_method_send = 0x0006, /**< rfc5766 - Send (only indication semantics defined) */ + tnet_stun_method_data = 0x0007, /**< rfc5766 - Data (only indication semantics defined) */ + tnet_stun_method_createpermission = 0x0008, /**< rfc5766 - CreatePermission (only request/response semantics defined */ + tnet_stun_method_channelbind = 0x0009, /**< rfc5766 - ChannelBind (only request/response semantics defined) */ + tnet_stun_method_connect = 0x000a,/**< rfc6062 - Connect */ + tnet_stun_method_connectionbind = 0x000b,/**< rfc6062 - ConnectionBind */ + tnet_stun_method_connectionattempt = 0x000c,/**< rfc6062 - ConnectionAttempt */ +} +tnet_stun_method_t; + +/**@ingroup tnet_stun_group +*/ +typedef enum tnet_stun_mask_e { + tnet_stun_mask_request = 0x0000, + tnet_stun_mask_indication = 0x0010, + tnet_stun_mask_success = 0x0100, + tnet_stun_mask_error = 0x0110 +} +tnet_stun_mask_t; + +/**@ingroup tnet_stun_group + * STUN IP family as per RFC 5389 subclause 15.1. +**/ +typedef enum tnet_stun_address_family_e { + tnet_stun_address_family_ipv4 = 0x01, + tnet_stun_address_family_ipv6 = 0x02 +} tnet_stun_address_family_t; + +// rfc5766 - 14.7. REQUESTED-TRANSPORT +typedef enum tnet_turn_transport_e { + tnet_turn_transport_udp = 17, + tnet_turn_transport_tcp = 6 +} +tnet_turn_transport_t; + +// RFC 5389 - 15.6. ERROR-CODE +#define kStunErrorClassTryAlternate 3 +#define kStunErrorNumberTryAlternate 0 +#define kStunErrorPhraseTryAlternate "Try Alternate" +#define kStunErrorClassBadRequest 4 +#define kStunErrorNumberBadRequest 0 +#define kStunErrorPhraseBadRequest "Bad Request" +#define kStunErrorClassUnauthorized 4 +#define kStunErrorNumberUnauthorized 1 +#define kStunErrorPhraseUnauthorized "Unauthorized" +#define kStunErrorClassUnknownAttribute 4 +#define kStunErrorNumberUnknownAttribute 20 +#define kStunErrorPhraseUnknownAttribute "Unknown Attribute" +#define kStunErrorClassStaleNonce 4 +#define kStunErrorNumberStaleNonce 38 +#define kStunErrorPhraseStaleNonce "Stale Nonce" +#define kStunErrorClassServerError 5 +#define kStunErrorNumberServerError 0 +#define kStunErrorPhraseServerError "Server Error" +// rfc5766 - 15. New STUN Error Response Codes +#define kStunErrorClassForbidden 4 +#define kStunErrorNumberForbidden 3 +#define kStunErrorPhraseForbidden "Forbidden" +#define kStunErrorClassAllocationMismatch 4 +#define kStunErrorNumberAllocationMismatch 37 +#define kStunErrorPhraseAllocationMismatch "Allocation Mismatch" +#define kStunErrorClassWrongCredentials 4 +#define kStunErrorNumberWrongCredentials 42 +#define kStunErrorPhraseWrongCredentials "Wrong Credentials" +#define kStunErrorClassUnsupportedTransportProtocol 4 +#define kStunErrorNumberUnsupportedTransportProtocol 42 +#define kStunErrorPhraseUnsupportedTransportProtocol "Unsupported Transport Protocol" +#define kStunErrorClassAllocationQuotaReached 4 +#define kStunErrorNumberAllocationQuotaReached 86 +#define kStunErrorPhraseAllocationQuotaReached "Allocation Quota Reached" +#define kStunErrorClassInsufficientCapacity 5 +#define kStunErrorNumberInsufficientCapacity 8 +#define kStunErrorPhraseInsufficientCapacity "Insufficient Capacity" + + +/**@ingroup tnet_stun_group + * STUN attr types as per RFC 5389 subclause 18.2. +**/ +typedef enum tnet_stun_attr_type_e { + /* === RFC 5389 - Comprehension-required range (0x0000-0x7FFF) */ + tnet_stun_attr_type_reserved = 0x0000, /**< (Reserved) */ + tnet_stun_attr_type_mapped_address = 0x0001, /**< http://tools.ietf.org/html/rfc5389#page-32 */ + tnet_stun_attr_type_response_address = 0x0002, /**< (Reserved; was RESPONSE-ADDRESS) */ + tnet_stun_attr_type_change_address = 0x0003, /**< (Reserved; was CHANGE-ADDRESS) */ + tnet_stun_attr_type_source_address = 0x0004, /**< (Reserved; was SOURCE-ADDRESS) */ + tnet_stun_attr_type_changed_address = 0x0005, /**< (Reserved; was CHANGED-ADDRESS) */ + tnet_stun_attr_type_username = 0x0006, /**< http://tools.ietf.org/html/rfc5389#page-34 */ + tnet_stun_attr_type_password = 0x0007, /**< (Reserved; was PASSWORD) */ + tnet_stun_attr_type_message_integrity = 0x0008, /**< http://tools.ietf.org/html/rfc5389#page-34 */ + tnet_stun_attr_type_error_code = 0x0009, /**< http://tools.ietf.org/html/rfc5389#page-36 */ + tnet_stun_attr_type_unknown_attrs = 0x000A, /**< http://tools.ietf.org/html/rfc5389#page-38 */ + tnet_stun_attr_type_reflected_from = 0x000B, /**< (Reserved; was REFLECTED-FROM) */ + tnet_stun_attr_type_realm = 0x0014, /**< http://tools.ietf.org/html/rfc5389#page-38 */ + tnet_stun_attr_type_nonce = 0x0015, /**< http://tools.ietf.org/html/rfc5389#page-38 */ + tnet_stun_attr_type_xor_mapped_address = 0x0020, /**< http://tools.ietf.org/html/rfc5389#page-33 */ + + /* === RFC 5389 - Comprehension-optional range (0x8000-0xFFFF) */ + tnet_stun_attr_type_software = 0x8022, /**< http://tools.ietf.org/html/rfc5389#page-39 */ + tnet_stun_attr_type_alternate_server = 0x8023, /**< http://tools.ietf.org/html/rfc5389#page-39 */ + tnet_stun_attr_type_fingerprint = 0x8028, /**< http://tools.ietf.org/html/rfc5389#page-36 */ + + /* === rfc5766 */ + tnet_stun_attr_type_channel_number = 0x000C, /**< rfc5766 - CHANNEL-NUMBER */ + tnet_stun_attr_type_lifetime = 0x000D, /**< rfc5766 - LIFETIME */ + tnet_stun_attr_type_reserved2 = 0x0010, /**< rfc5766 - Reserved (was BANDWIDTH) */ + tnet_stun_attr_type_xor_peer_address = 0x0012, /**< rfc5766 - XOR-PEER-ADDRESS */ + tnet_stun_attr_type_data = 0x0013, /**< rfc5766 - DATA */ + tnet_stun_attr_type_xor_relayed_address = 0x0016, /**< rfc5766 - XOR-RELAYED-ADDRESS */ + tnet_stun_attr_type_even_port = 0x0018, /**< rfc5766 - EVEN-PORT */ + tnet_stun_attr_type_requested_transport = 0x0019, /**< rfc5766 - REQUESTED-TRANSPORT */ + tnet_stun_attr_type_dont_fragment = 0x001A, /**< rfc5766 - DONT-FRAGMENT */ + tnet_stun_attr_type_reserved3 = 0x0021, /**< rfc5766 - Reserved (was TIMER-VAL) */ + tnet_stun_attr_type_reservation_token = 0x0022, /**< rfc5766 - RESERVATION-TOKEN */ + + /* RFC 5245 */ + tnet_stun_attr_type_ice_priority = 0x0024, /**< 21.2. STUN Attributes */ + tnet_stun_attr_type_ice_use_candidate = 0x0025, /**< 21.2. STUN Attributes */ + tnet_stun_attr_type_ice_controlled = 0x8029, /**< 21.2. STUN Attributes */ + tnet_stun_attr_type_ice_controlling = 0x802A, /**< 21.2. STUN Attributes */ + + /* rfc6062 */ + tnet_stun_attr_type_connection_id = 0x002a, /**< 6.2. New STUN Attributes */ +} tnet_stun_attr_type_t; + + +/**@ingroup tnet_stun_group +* List of all supported STUN message types. +*/ +typedef enum tnet_stun_pkt_type_e { + /* RFC 5389 - 6. STUN Message Structure + + The message type defines the message class (request, success + response, failure response, or indication) and the message method + (the primary function) of the STUN message. Although there are four + message classes, there are only two types of transactions in STUN: + request/response transactions (which consist of a request message and + a response message) and indication transactions (which consist of a + single indication message). Response classes are split into error + and success responses to aid in quickly processing the STUN message. + + The message type field is decomposed further into the following + structure: + + 0 1 + 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + |M |M |M|M|M|C|M|M|M|C|M|M|M|M| + |11|10|9|8|7|1|6|5|4|0|3|2|1|0| + +--+--+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + tnet_stun_pkt_type_binding_request = (tnet_stun_method_binding | tnet_stun_mask_request), + tnet_stun_pkt_type_binding_indication = (tnet_stun_method_binding | tnet_stun_mask_indication), + tnet_stun_pkt_type_binding_success_response = (tnet_stun_method_binding | tnet_stun_mask_success), + tnet_stun_pkt_type_binding_error_response = (tnet_stun_method_binding | tnet_stun_mask_error), + + tnet_stun_pkt_type_allocate_request = (tnet_stun_method_allocate | tnet_stun_mask_request), + tnet_stun_pkt_type_allocate_indication = (tnet_stun_method_allocate | tnet_stun_mask_indication), + tnet_stun_pkt_type_allocate_success_response = (tnet_stun_method_allocate | tnet_stun_mask_success), + tnet_stun_pkt_type_allocate_error_response = (tnet_stun_method_allocate | tnet_stun_mask_error), + + tnet_stun_pkt_type_refresh_request = (tnet_stun_method_refresh | tnet_stun_mask_request), + tnet_stun_pkt_type_refresh_indication = (tnet_stun_method_refresh | tnet_stun_mask_indication), + tnet_stun_pkt_type_refresh_success_response = (tnet_stun_method_refresh | tnet_stun_mask_success), + tnet_stun_pkt_type_refresh_error_response = (tnet_stun_method_refresh | tnet_stun_mask_error), + + tnet_stun_pkt_type_send_indication = (tnet_stun_method_send | tnet_stun_mask_indication), + + tnet_stun_pkt_type_data_indication = (tnet_stun_method_data | tnet_stun_mask_indication), + + tnet_stun_pkt_type_createpermission_request = (tnet_stun_method_createpermission | tnet_stun_mask_request), + tnet_stun_pkt_type_createpermission_indication = (tnet_stun_method_createpermission | tnet_stun_mask_indication), + tnet_stun_pkt_type_createpermission_success_response = (tnet_stun_method_createpermission | tnet_stun_mask_success), + tnet_stun_pkt_type_createpermission_error_response = (tnet_stun_method_createpermission | tnet_stun_mask_error), + + tnet_stun_pkt_type_channelbind_request = (tnet_stun_method_channelbind | tnet_stun_mask_request), + tnet_stun_pkt_type_channelbind_indication = (tnet_stun_method_channelbind | tnet_stun_mask_indication), + tnet_stun_pkt_type_channelbind_success_response = (tnet_stun_method_channelbind | tnet_stun_mask_success), + tnet_stun_pkt_type_channelbind_error_response = (tnet_stun_method_channelbind | tnet_stun_mask_error), + + tnet_stun_pkt_type_connect_request = (tnet_stun_method_connect | tnet_stun_mask_request), + tnet_stun_pkt_type_connect_indication = (tnet_stun_method_connect | tnet_stun_mask_indication), + tnet_stun_pkt_type_connect_success_response = (tnet_stun_method_connect | tnet_stun_mask_success), + tnet_stun_pkt_type_connect_error_response = (tnet_stun_method_connect | tnet_stun_mask_error), + + tnet_stun_pkt_type_connectionbind_request = (tnet_stun_method_connectionbind | tnet_stun_mask_request), + tnet_stun_pkt_type_connectionbind_indication = (tnet_stun_method_connectionbind | tnet_stun_mask_indication), + tnet_stun_pkt_type_connectionbind_success_response = (tnet_stun_method_connectionbind | tnet_stun_mask_success), + tnet_stun_pkt_type_connectionbind_error_response = (tnet_stun_method_connectionbind | tnet_stun_mask_error), + + tnet_stun_pkt_type_connectionattempt_indication = (tnet_stun_method_connectionattempt | tnet_stun_mask_indication), +} +tnet_stun_pkt_type_t; + +/* RFC 5389 - 7.2.1. Sending over UDP + A client SHOULD retransmit a STUN request message starting with an + interval of RTO ("Retransmission TimeOut"), doubling after each + retransmission. + + e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms + */ +#define kStunUdpRetransmitTimoutMinInMs 500 +#define kStunUdpRetransmitTimoutMaxInMs 31500 + +// rfc5766 - 2.2. Allocations +#if !defined(kTurnAllocationTimeOutInSec) +# define kTurnAllocationTimeOutInSec 600 /* 10min */ // FIXME +#endif /* kTurnAllocationTimeOutInSec */ + +// rfc5766 - 2.3. Permissions +#if !defined(kTurnPermissionTimeOutInSec) +# define kTurnPermissionTimeOutInSec 300 /* 5min */ +#endif /* kTurnPermissionTimeOutInSec */ + +// rfc5766 - 2.5. Channels +#if !defined(kTurnChannelBindingTimeOutInSec) +# define kTurnChannelBindingTimeOutInSec 600 /* 10min */ +#endif /* kTurnChannelBindingTimeOutInSec */ + +// rfc5766 - 11.4. The ChannelData Message +#if !defined(kStunChannelDataHdrSizeInOctets) +# define kStunChannelDataHdrSizeInOctets 4 +#endif /* kStunChannelDataHdrSizeInOctets */ + +// Not part of the standard +typedef enum tnet_stun_state_e { + tnet_stun_state_none, + tnet_stun_state_trying, + tnet_stun_state_ok, + tnet_stun_state_nok +} tnet_stun_state_t; + +TNET_END_DECLS + +#endif /* TNET_STUN_TYPES_H */ diff --git a/tinyNET/src/stun/tnet_stun_utils.c b/tinyNET/src/stun/tnet_stun_utils.c new file mode 100644 index 0000000..8e35075 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_utils.c @@ -0,0 +1,201 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#include "stun/tnet_stun_utils.h" +#include "stun/tnet_stun_pkt.h" +#include "stun/tnet_stun_attr.h" + +#include "tnet_utils.h" + +#include "tsk_memory.h" +#include "tsk_debug.h" + +int tnet_stun_utils_inet_pton(tsk_bool_t b_v6, const char* p_src, tnet_stun_addr_t* p_dst) +{ + int ret; + if (!p_src || !p_dst) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if ((ret = tnet_inet_pton(b_v6 ? AF_INET6 : AF_INET, p_src, *p_dst) != 1)) { // success == 1 + TSK_DEBUG_ERROR("tnet_inet_pton() with error code = %d", ret); + return -3; + } + return 0; +} + +int tnet_stun_utils_inet_ntop(tsk_bool_t b_v6, const tnet_stun_addr_t* pc_src, tnet_ip_t* p_dst) +{ + if (!pc_src || !p_dst) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + if (tnet_inet_ntop(b_v6 ? AF_INET6 : AF_INET, *pc_src, *p_dst, sizeof(*p_dst)) == tsk_null) { + TSK_DEBUG_ERROR("tnet_inet_ntop() failed"); + return -2; + } + return 0; +} + +int tnet_stun_utils_transac_id_rand(tnet_stun_transac_id_t* p_transac_id) +{ + tsk_size_t u; + static tsk_size_t __u_size = sizeof(tnet_stun_transac_id_t); + static long __l_chan_num = 0; + + tsk_atomic_inc(&__l_chan_num); + + if (!p_transac_id) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + for (u = 0; (u < __u_size) && (u < sizeof(long)); ++u) { + *(((uint8_t*)p_transac_id) + u) = (__l_chan_num >> (u << 3)) & 0xFF; + } + for (u = sizeof(long); u < __u_size; ++u) { + *(((uint8_t*)p_transac_id) + u) = rand() % 0xFF; + } + return 0; +} + +int tnet_stun_utils_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size) +{ + int ret; + tsk_size_t u; + if (!pc_buf1_ptr || !pc_buf2_ptr || (n_buff1_size != n_buff2_size)) { + return -1; + } + for (u = 0; u < n_buff1_size; ++u) { + if ((ret = (pc_buf1_ptr[u] - pc_buf2_ptr[u]))) { + return ret; + } + } + return 0; +} + +int tnet_stun_utils_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const struct tnet_stun_pkt_s* pc_stun_req, struct sockaddr* p_addr_server, struct tnet_stun_pkt_s** pp_stun_resp) +{ + int ret = -1; + uint16_t i, rto = RTO; + struct timeval tv; + fd_set set; + void* p_buff_ptr = tsk_null; + tsk_size_t u_buff_size; + + if (!pc_stun_req || !p_addr_server || !pp_stun_resp) { + TSK_DEBUG_ERROR("Invalid parameter"); + return -1; + } + /* RFC 5389 - 7.2.1. Sending over UDP + STUN indications are not retransmitted; thus, indication transactions over UDP + are not reliable. + */ + *pp_stun_resp = tsk_null; + tv.tv_sec = 0; + tv.tv_usec = 0; + + if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_stun_req, &u_buff_size))) { + goto bail; + } + u_buff_size += kStunBuffMinPad; + if (!(p_buff_ptr = tsk_malloc(u_buff_size))) { + goto bail; + } + if ((ret = tnet_stun_pkt_write_with_padding(pc_stun_req, p_buff_ptr, u_buff_size, &u_buff_size))) { + goto bail; + } + + /* RFC 5389 - 7.2.1. Sending over UDP + A client SHOULD retransmit a STUN request message starting with an + interval of RTO ("Retransmission TimeOut"), doubling after each + retransmission. + + e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms + */ + for (i = 0; i < Rc; i++) { + tv.tv_sec += rto/1000; + tv.tv_usec += (rto% 1000) * 1000; + if (tv.tv_usec >= 1000000) { + tv.tv_usec -= 1000000; + tv.tv_sec++; + } + + FD_ZERO(&set); + FD_SET(localFD, &set); + + if ((ret = tnet_sockfd_sendto(localFD, p_addr_server, p_buff_ptr, u_buff_size))) { + // do nothing... not an error + } + + if ((ret = select(localFD+1, &set, NULL, NULL, &tv)) < 0) { + goto bail; + } + else if (ret == 0) { + /* timeout */ + TSK_DEBUG_INFO("STUN request timedout at %d", i); + rto *= 2; + continue; + } + else if (FD_ISSET(localFD, &set)) { + /* there is data to read */ + + unsigned int len = 0; + void* data = 0; + + TSK_DEBUG_INFO("STUN request got response"); + + /* Check how how many bytes are pending */ + if ((ret = tnet_ioctlt(localFD, FIONREAD, &len)) < 0) { + goto bail; + } + + if(len == 0) { + TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes"); + continue; + } + + /* Receive pending data */ + data = tsk_malloc(len); + if ((ret = tnet_sockfd_recvfrom(localFD, data, len, 0, p_addr_server)) < 0) { + TSK_FREE(data); + + TSK_DEBUG_ERROR("Recv STUN dgrams failed with error code:%d", tnet_geterrno()); + goto bail; + } + + /* Parse the incoming response. */ + ret = tnet_stun_pkt_read(data, (tsk_size_t)ret, pp_stun_resp); + TSK_FREE(data); + if (*pp_stun_resp) { + if (tnet_stun_utils_transac_id_cmp((*pp_stun_resp)->transac_id, pc_stun_req->transac_id) != 0) { + /* Not same transaction id */ + TSK_OBJECT_SAFE_FREE(*pp_stun_resp); + continue; + } + } + goto bail; + } + else { + continue; + } + } + +bail: + TSK_FREE(p_buff_ptr); + return (*pp_stun_resp) ? 0 : -4; +} diff --git a/tinyNET/src/stun/tnet_stun_utils.h b/tinyNET/src/stun/tnet_stun_utils.h new file mode 100644 index 0000000..c2999c7 --- /dev/null +++ b/tinyNET/src/stun/tnet_stun_utils.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2014 Mamadou DIOP. +* +* 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 Lesser General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with DOUBANGO. +* +*/ +#ifndef TNET_STUN_UTILS_H +#define TNET_STUN_UTILS_H + +#include "tinynet_config.h" +#include "stun/tnet_stun_types.h" + +#include "tnet_types.h" + +struct tnet_stun_pkt_s; + +TNET_BEGIN_DECLS + +TINYNET_API int tnet_stun_utils_inet_pton(tsk_bool_t b_v6, const char* p_src, tnet_stun_addr_t* p_dst); +#define tnet_stun_utils_inet_pton_v4(p_src, p_dst) tnet_stun_utils_inet_pton(tsk_false, (p_src), (p_dst)) +#define tnet_stun_utils_inet_pton_v6(p_src, p_dst) tnet_stun_utils_inet_pton(tsk_true, (p_src), (p_dst)) +TINYNET_API int tnet_stun_utils_inet_ntop(tsk_bool_t b_v6, const tnet_stun_addr_t* pc_src, tnet_ip_t* p_dst); +#define tnet_stun_utils_inet_ntop_v4(pc_src, p_dst) tnet_stun_utils_inet_ntop(tsk_false, (pc_src), (p_dst)) +#define tnet_stun_utils_inet_ntop_v6(pc_src, p_dst) tnet_stun_utils_inet_ntop(tsk_true, (pc_src), (p_dst)) +TINYNET_API int tnet_stun_utils_transac_id_rand(tnet_stun_transac_id_t* p_transac_id); +TINYNET_API int tnet_stun_utils_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size); +#define tnet_stun_utils_transac_id_cmp(pc_tid1, pc_tid2) tnet_stun_utils_buff_cmp((pc_tid1), sizeof(tnet_stun_transac_id_t), (pc_tid2), sizeof(tnet_stun_transac_id_t)) +#define tnet_stun_utils_transac_id_equals(pc_tid1, pc_tid2) (tnet_stun_utils_transac_id_cmp((pc_tid1), (pc_tid2)) == 0) +int tnet_stun_utils_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const struct tnet_stun_pkt_s* pc_stun_req, struct sockaddr* p_addr_server, struct tnet_stun_pkt_s** pp_stun_resp); + +TNET_END_DECLS + +#endif /* TNET_STUN_UTILS_H */ |