summaryrefslogtreecommitdiffstats
path: root/tinyNET/src/stun
diff options
context:
space:
mode:
Diffstat (limited to 'tinyNET/src/stun')
-rw-r--r--tinyNET/src/stun/tnet_stun.c440
-rw-r--r--tinyNET/src/stun/tnet_stun.h128
-rw-r--r--tinyNET/src/stun/tnet_stun_attribute.c960
-rw-r--r--tinyNET/src/stun/tnet_stun_attribute.h329
-rw-r--r--tinyNET/src/stun/tnet_stun_message.c440
-rw-r--r--tinyNET/src/stun/tnet_stun_message.h240
6 files changed, 2537 insertions, 0 deletions
diff --git a/tinyNET/src/stun/tnet_stun.c b/tinyNET/src/stun/tnet_stun.c
new file mode 100644
index 0000000..5faa974
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun.c
@@ -0,0 +1,440 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun.c
+ * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#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_message_t *tnet_stun_create_request(const tnet_stun_binding_t* binding)
+{
+ tnet_stun_message_t *message = tnet_stun_message_create(binding->username, binding->password);
+ message->realm = tsk_strdup(binding->realm);
+ message->nonce = tsk_strdup(binding->nonce);
+
+ if(message){
+ /* 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->transaction_id, digest, TNET_STUN_TRANSACID_SIZE);
+ }
+
+ /* Add software attribute */
+ if(binding->software){
+ tnet_stun_attribute_t* attribute = (tnet_stun_attribute_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_message_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_response_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_message_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_message_serialize(message);
+ tnet_stun_response_t *response = 0;
+
+ 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->transaction_id, response->transaction_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_response_t *response = 0;
+ tnet_stun_request_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_RESPONSE_IS_ERROR(response)){
+ short code = tnet_stun_message_get_errorcode(response);
+ const char* realm = tnet_stun_message_get_realm(response);
+ const char* nonce = tnet_stun_message_get_nonce(response);
+
+ if(code == 401 && realm && nonce){
+ if(!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_attribute_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 TNET_STUN_INVALID_BINDING_ID 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 = TNET_STUN_INVALID_BINDING_ID;
+
+ 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_transacid_t id1, const tnet_stun_transacid_t id2)
+{
+ tsk_size_t i;
+ for(i=0; i<sizeof(tnet_stun_transacid_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*));
+
+ 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..05933ca
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun.h
@@ -0,0 +1,128 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun.h
+ * @brief Session Traversal Utilities for NAT (STUN) implementation as per RFC 5389 and RFC 3489(Obsolete).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#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 TNET_STUN_INVALID_BINDING_ID
+ * STUN2 invalid binding id.
+**/
+/**@ingroup tnet_stun_group
+ * @def TNET_STUN_IS_VALID_BINDING_ID
+ * Checks the validity of the STUN @a id.
+**/
+#define TNET_STUN_INVALID_BINDING_ID 0
+#define TNET_STUN_IS_VALID_BINDING_ID(id) (id != TNET_STUN_INVALID_BINDING_ID)
+
+/**@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 TNET_STUN_MAGIC_COOKIE 0x2112A442
+
+/**@ingroup tnet_stun_group
+ * STUN2 header size as per RFC 5389 subclause 6.
+**/
+#define TNET_STUN_HEADER_SIZE 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 tnet_nat_context_s;
+//#endif
+
+int tnet_stun_send_reliably(const tnet_stun_message_t* message);
+tnet_stun_response_t* tnet_stun_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const tnet_stun_message_t* message, struct sockaddr* server);
+TINYNET_API tnet_stun_binding_id_t tnet_stun_bind(const struct tnet_nat_context_s* nat_context, tnet_fd_t localFD);
+int tnet_stun_transacid_cmp(const tnet_stun_transacid_t id1, const tnet_stun_transacid_t id2);
+
+TNET_END_DECLS
+
+
+#endif /* TNET_STUN_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..feb6909
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attribute.c
@@ -0,0 +1,960 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun_attribute.c
+ * @brief STUN2(RFC 5389) attribute parser.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_stun_attribute.h"
+
+#include "tnet_stun.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "../turn/tnet_turn_attribute.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_attribute_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
+* Creates @ref tnet_stun_attribute_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_attribute_t object if succeed and NULL other wise.
+*/
+tnet_stun_attribute_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_stun_attribute_t *attribute = 0;
+ const uint8_t* dataPtr = data;
+
+ tnet_stun_attribute_type_t type = (tnet_stun_attribute_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_attribute_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_attribute_t *)tnet_stun_attribute_xmapped_address_create(dataPtr, length);
+ break;
+ }
+
+ /* RFC 5389 - 15.3. USERNAME*/
+ case stun_username:
+ {
+ attribute = (tnet_stun_attribute_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_attribute_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_attribute_t *)tnet_stun_attribute_fingerprint_create(fingerprint);
+ break;
+ }
+
+ /* RFC 5389 - 15.6. ERROR-CODE*/
+ case stun_error_code:
+ {
+ attribute = (tnet_stun_attribute_t *)tnet_stun_attribute_errorcode_create(dataPtr, length);
+ break;
+ }
+
+ /* RFC 5389 - 15.7. REALM*/
+ case stun_realm:
+ {
+ attribute = (tnet_stun_attribute_t *)tnet_stun_attribute_realm_create(dataPtr, length);
+ break;
+ }
+
+ /* RFC 5389 - 15.8. NONCE*/
+ case stun_nonce:
+ {
+ attribute = (tnet_stun_attribute_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_attribute_t *)tnet_stun_attribute_software_create(dataPtr, length);
+ break;
+ }
+
+ /* RFC 5389 - 15.11. ALTERNATE-SERVER */
+ case stun_alternate_server:
+ {
+ attribute = (tnet_stun_attribute_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);
+ 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_attribute_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_attribute_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
+ */
+
+ switch(attribute->type){
+ /* RFC 5389 - 15.1. MAPPED-ADDRESS */
+ case stun_mapped_address:
+ {
+ TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* RFC 5389 - 15.2. XOR-MAPPED-ADDRESS*/
+ case stun_xor_mapped_address:
+ {
+ TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* 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:
+ {
+ TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* 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 tnet_turn_attribute_serialize(attribute, output);
+ }
+
+ 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_attribute_t* attribute, tsk_buffer_t *output)
+{
+ if(attribute->length%4){
+ static uint32_t zeros = 0x00000000;
+ tsk_buffer_append(output, &zeros, 4-(attribute->length%4));
+ }
+}
+
+
+
+
+//=================================================================================================
+// [[RFC 5389 - 15. STUN Attributes]] object definition
+//
+static tsk_object_t* tnet_stun_attribute_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_attribute_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_stun_attribute_dtor(tsk_object_t * self)
+{
+ tnet_stun_attribute_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_stun_attribute_def_s =
+{
+ sizeof(tnet_stun_attribute_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 */
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_mapped_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+
+ 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);
+ }
+ }
+ }
+ }
+ 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 */
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_mapped_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+
+ 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) ^ TNET_STUN_MAGIC_COOKIE);
+ memcpy(&attribute->xaddress[i], &addr, 4);
+ payloadPtr+=4;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+ }
+ }
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_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;
+
diff --git a/tinyNET/src/stun/tnet_stun_attribute.h b/tinyNET/src/stun/tnet_stun_attribute.h
new file mode 100644
index 0000000..66fd7ff
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_attribute.h
@@ -0,0 +1,329 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun_attribute.h
+ * @brief STUN2(RFC 5389) attribute parser.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#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_attribute_t pointer.
+* @param self The attribute to convert (cast).
+* @retval A pointer to @ref tnet_stun_attribute_t object.
+*/
+TNET_BEGIN_DECLS
+
+#define TNET_STUN_ATTRIBUTE(self) ((tnet_stun_attribute_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_attribute_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 */
+}
+tnet_stun_attribute_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_attribute_type_t type;
+ uint16_t length;
+}
+tnet_stun_attribute_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_attribute_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;
+
+
+tnet_stun_attribute_t* tnet_stun_attribute_deserialize(const void* data, tsk_size_t size);
+int tnet_stun_attribute_serialize(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output);
+void tnet_stun_attribute_pad(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output);
+
+
+
+
+tnet_stun_attribute_t* tnet_stun_attribute_create();
+tnet_stun_attribute_mapped_addr_t* tnet_stun_attribute_mapped_address_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_xmapped_addr_t* tnet_stun_attribute_xmapped_address_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_username_t* tnet_stun_attribute_username_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_integrity_t* tnet_stun_attribute_integrity_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_fingerprint_t* tnet_stun_attribute_fingerprint_create(uint32_t fingerprint);
+tnet_stun_attribute_errorcode_t* tnet_stun_attribute_errorcode_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_realm_t* tnet_stun_attribute_realm_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_nonce_t* tnet_stun_attribute_nonce_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_unknowns_t* tnet_stun_attribute_unknowns_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_software_t* tnet_stun_attribute_software_create(const void* payload, tsk_size_t payload_size);
+tnet_stun_attribute_altserver_t* tnet_stun_attribute_altserver_create(const void* payload, tsk_size_t payload_size);
+
+
+TNET_END_DECLS
+
+#endif /* TNET_STUN_ATTRIBUTE_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..9769092
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_message.c
@@ -0,0 +1,440 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun_message.c
+ * @brief STUN2 (RFC 5389) message parser.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_stun_message.h"
+
+#include "tnet_stun.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+#include "../turn/tnet_turn_attribute.h"
+
+#include "tsk_memory.h"
+#include "tsk_hmac.h"
+#include "tsk_string.h"
+#include "tsk_ppfcs32.h"
+
+#include <string.h>
+
+
+/**@ingroup tnet_stun_group
+* Creates new STUN message.
+* @retval @ref tnet_stun_message_t object.
+* @sa tnet_stun_message_create_null.
+*/
+
+tnet_stun_message_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_message_t object.
+* @sa tnet_stun_message_create.
+*/
+tnet_stun_message_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_attribute_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_message_serialize(const tnet_stun_message_t *self)
+{
+ tsk_buffer_t *output = 0;
+ tnet_stun_attribute_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. */
+ {
+ 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->transaction_id, TNET_STUN_TRANSACID_SIZE);
+
+ /* DONT-FRAGMENT
+ */
+ if(self->dontfrag){
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_dontfrag_create();
+ tnet_stun_attribute_serialize(attribute, output);
+ TSK_OBJECT_SAFE_FREE(attribute);
+ }
+
+ /*=== 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);
+ }
+ }
+
+ /* AUTHENTICATION */
+ if(self->realm && self->nonce){
+ SERIALIZE_N_ADD_ATTRIBUTE(username, self->username, tsk_strlen(self->username));
+ SERIALIZE_N_ADD_ATTRIBUTE(realm, self->realm, tsk_strlen(self->realm));
+ SERIALIZE_N_ADD_ATTRIBUTE(nonce, self->nonce, tsk_strlen(self->nonce));
+
+ compute_integrity = 1;
+ }
+
+ /* Message Length: The message length MUST contain the size, in bytes, of the message
+ not including the 20-byte STUN header.
+ */
+ {
+ uint16_t length = (output->size) - TNET_STUN_HEADER_SIZE;
+ if(self->fingerprint)
+ length += (2/* Type */ + 2 /* Length */+ 4 /* FINGERPRINT VALUE*/);
+
+ if(compute_integrity)
+ length += (2/* Type */ + 2 /* Length */+ TSK_SHA1_DIGEST_SIZE /* INTEGRITY VALUE*/);
+
+ *(((uint16_t*)output->data)+1) = tnet_htons(length);
+ }
+
+ /* MESSAGE-INTEGRITY */
+ if(compute_integrity){
+ /* RFC 5389 - 15.4. MESSAGE-INTEGRITY
+ The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of the STUN message.
+
+ For long-term credentials ==> key = MD5(username ":" realm ":" SASLprep(password))
+ For short-term credentials ==> key = SASLprep(password)
+ FIXME: what about short term credentials?
+ FIXME: what about SASLprep
+ */
+ char* keystr = 0;
+ tsk_sha1digest_t hmac;
+ 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);
+
+ SERIALIZE_N_ADD_ATTRIBUTE(integrity, hmac, TSK_SHA1_DIGEST_SIZE);
+
+ TSK_FREE(keystr);
+ }
+
+ /* FINGERPRINT */
+ if(self->fingerprint){
+ /* 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_attribute_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_message_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size)
+{
+ tnet_stun_message_t *message = 0;
+ uint8_t* dataPtr, *dataEnd;
+
+
+ if(!data || (size < TNET_STUN_HEADER_SIZE) || !TNET_IS_STUN2(data))
+ {
+ goto bail;
+ }
+
+ dataPtr = (uint8_t*)data;
+ dataEnd = (dataPtr + size);
+
+ message = tnet_stun_message_create_null();
+
+ /* Message Type
+ */
+ message->type = (tnet_stun_message_type_t)tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ /* Message Length
+ */
+ message->length = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ /* Check message validity
+ */
+ if((message->length + TNET_STUN_HEADER_SIZE) != 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->transaction_id, dataPtr, TNET_STUN_TRANSACID_SIZE);
+ dataPtr += TNET_STUN_TRANSACID_SIZE;
+
+ /* == Parse attributes
+ */
+ while(dataPtr < dataEnd){
+ tnet_stun_attribute_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%4) ? 4-(att_size%4) : 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
+* 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_message_t *self, tnet_stun_attribute_t** attribute)
+{
+ //if(self && attribute)
+ {
+ tsk_list_push_back_data(self->attributes, (void**)attribute);
+ return 0;
+ }
+ return -1;
+}
+
+/**@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_attribute_t object if found and NULL otherwise.
+*/
+const tnet_stun_attribute_t* tnet_stun_message_get_attribute(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type)
+{
+ tnet_stun_attribute_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_message_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_message_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_message_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_message_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;
+}
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// STUN2 MESSAGE object definition
+//
+static tsk_object_t* tnet_stun_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_stun_message_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 = TNET_STUN_MAGIC_COOKIE;
+ message->attributes = tsk_list_create();
+
+ message->fingerprint = 1;
+ message->integrity = 0;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_stun_message_dtor(tsk_object_t * self)
+{
+ tnet_stun_message_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_message_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..862c7b6
--- /dev/null
+++ b/tinyNET/src/stun/tnet_stun_message.h
@@ -0,0 +1,240 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_stun_message.h
+ * @brief STUN2 (RFC 5389) message parser.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#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_RESPONSE_IS_REQUEST
+* Checks whether the STUN message is a request or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_RESPONSE_IS_INDICATION
+* Checks whether the STUN message is an indicaton message or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_RESPONSE_IS_SUCCESS
+* Checks whether the STUN message is a success response or not.
+*/
+/**@ingroup tnet_stun_group
+* @def TNET_STUN_RESPONSE_IS_ERROR
+* Checks whether the STUN message is an error response or not.
+*/
+#define TNET_STUN_RESPONSE_IS_REQUEST(self) ((self->type & TNET_STUN_CLASS_REQUEST_MASK) == TNET_STUN_CLASS_REQUEST_MASK)
+#define TNET_STUN_RESPONSE_IS_INDICATION(self) ((self->type & TNET_STUN_CLASS_INDICATION_MASK) == TNET_STUN_CLASS_INDICATION_MASK)
+#define TNET_STUN_RESPONSE_IS_SUCCESS(self) ((self->type & TNET_STUN_CLASS_SUCCESS_MASK) == TNET_STUN_CLASS_SUCCESS_MASK)
+#define TNET_STUN_RESPONSE_IS_ERROR(self) ((self->type & TNET_STUN_CLASS_ERROR_MASK) == 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_IS_STUN2(PU8) \
+ (((PU8)[0] & 0xc0) == 0x00) && \
+ ( (*(((uint32_t *)(PU8))+1)) == tnet_htonl(TNET_STUN_MAGIC_COOKIE) )
+
+/**@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_transacid_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_message_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_message_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_message_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_message_type_t type;
+ uint16_t length;
+ uint32_t cookie;
+ tnet_stun_transacid_t transaction_id;
+
+ unsigned fingerprint:1;
+ unsigned integrity:1;
+ unsigned dontfrag: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_message_t;
+
+typedef tnet_stun_message_t tnet_stun_response_t;
+typedef tnet_stun_message_t tnet_stun_request_t;
+
+tsk_buffer_t* tnet_stun_message_serialize(const tnet_stun_message_t *message);
+tnet_stun_message_t* tnet_stun_message_deserialize(const uint8_t *data, tsk_size_t size);
+int tnet_stun_message_add_attribute(tnet_stun_message_t *self, tnet_stun_attribute_t** attribute);
+const tnet_stun_attribute_t* tnet_stun_message_get_attribute(const tnet_stun_message_t *self, tnet_stun_attribute_type_t type);
+short tnet_stun_message_get_errorcode(const tnet_stun_message_t *self);
+const char* tnet_stun_message_get_realm(const tnet_stun_message_t *self);
+const char* tnet_stun_message_get_nonce(const tnet_stun_message_t *self);
+int32_t tnet_stun_message_get_lifetime(const tnet_stun_message_t *self);
+
+
+tnet_stun_message_t* tnet_stun_message_create(const char* username, const char* password);
+tnet_stun_message_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 */
+
OpenPOWER on IntegriCloud