summaryrefslogtreecommitdiffstats
path: root/tinyNET/src
diff options
context:
space:
mode:
Diffstat (limited to 'tinyNET/src')
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp.c338
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp.h121
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_message.c355
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_message.h226
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option.c326
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option.h291
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option_sip.c131
-rw-r--r--tinyNET/src/dhcp/tnet_dhcp_option_sip.h62
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6.c269
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6.h128
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_duid.c288
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_duid.h185
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_message.c137
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_message.h143
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_option.c336
-rw-r--r--tinyNET/src/dhcp6/tnet_dhcp6_option.h246
-rw-r--r--tinyNET/src/dns/tnet_dns.c973
-rw-r--r--tinyNET/src/dns/tnet_dns.h125
-rw-r--r--tinyNET/src/dns/tnet_dns_a.c106
-rw-r--r--tinyNET/src/dns/tnet_dns_a.h61
-rw-r--r--tinyNET/src/dns/tnet_dns_aaaa.c108
-rw-r--r--tinyNET/src/dns/tnet_dns_aaaa.h58
-rw-r--r--tinyNET/src/dns/tnet_dns_cname.c97
-rw-r--r--tinyNET/src/dns/tnet_dns_cname.h63
-rw-r--r--tinyNET/src/dns/tnet_dns_message.c364
-rw-r--r--tinyNET/src/dns/tnet_dns_message.h209
-rw-r--r--tinyNET/src/dns/tnet_dns_mx.c99
-rw-r--r--tinyNET/src/dns/tnet_dns_mx.h66
-rw-r--r--tinyNET/src/dns/tnet_dns_naptr.c146
-rw-r--r--tinyNET/src/dns/tnet_dns_naptr.h81
-rw-r--r--tinyNET/src/dns/tnet_dns_ns.c96
-rw-r--r--tinyNET/src/dns/tnet_dns_ns.h63
-rw-r--r--tinyNET/src/dns/tnet_dns_opt.c91
-rw-r--r--tinyNET/src/dns/tnet_dns_opt.h54
-rw-r--r--tinyNET/src/dns/tnet_dns_ptr.c97
-rw-r--r--tinyNET/src/dns/tnet_dns_ptr.h61
-rw-r--r--tinyNET/src/dns/tnet_dns_regexp.c508
-rw-r--r--tinyNET/src/dns/tnet_dns_regexp.h41
-rw-r--r--tinyNET/src/dns/tnet_dns_resolvconf.c301
-rw-r--r--tinyNET/src/dns/tnet_dns_resolvconf.h43
-rw-r--r--tinyNET/src/dns/tnet_dns_rr.c452
-rw-r--r--tinyNET/src/dns/tnet_dns_rr.h171
-rw-r--r--tinyNET/src/dns/tnet_dns_soa.c112
-rw-r--r--tinyNET/src/dns/tnet_dns_soa.h82
-rw-r--r--tinyNET/src/dns/tnet_dns_srv.c137
-rw-r--r--tinyNET/src/dns/tnet_dns_srv.h59
-rw-r--r--tinyNET/src/dns/tnet_dns_txt.c96
-rw-r--r--tinyNET/src/dns/tnet_dns_txt.h61
-rw-r--r--tinyNET/src/ice/tnet_ice.c32
-rw-r--r--tinyNET/src/ice/tnet_ice.h42
-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
-rw-r--r--tinyNET/src/tinynet.h58
-rw-r--r--tinyNET/src/tinynet_config.h120
-rw-r--r--tinyNET/src/tls/tnet_tls.c486
-rw-r--r--tinyNET/src/tls/tnet_tls.h57
-rw-r--r--tinyNET/src/tnet.c143
-rw-r--r--tinyNET/src/tnet.h45
-rw-r--r--tinyNET/src/tnet_auth.c30
-rw-r--r--tinyNET/src/tnet_auth.h39
-rw-r--r--tinyNET/src/tnet_endianness.c98
-rw-r--r--tinyNET/src/tnet_endianness.h53
-rw-r--r--tinyNET/src/tnet_hardwares.h64
-rw-r--r--tinyNET/src/tnet_nat.c570
-rw-r--r--tinyNET/src/tnet_nat.h120
-rw-r--r--tinyNET/src/tnet_poll.c109
-rw-r--r--tinyNET/src/tnet_poll.h92
-rw-r--r--tinyNET/src/tnet_proto.h196
-rw-r--r--tinyNET/src/tnet_socket.c326
-rw-r--r--tinyNET/src/tnet_socket.h167
-rw-r--r--tinyNET/src/tnet_transport.c494
-rw-r--r--tinyNET/src/tnet_transport.h143
-rw-r--r--tinyNET/src/tnet_transport_poll.c829
-rw-r--r--tinyNET/src/tnet_transport_win32.c786
-rw-r--r--tinyNET/src/tnet_types.h111
-rw-r--r--tinyNET/src/tnet_utils.c1593
-rw-r--r--tinyNET/src/tnet_utils.h176
-rw-r--r--tinyNET/src/turn/tnet_turn.c700
-rw-r--r--tinyNET/src/turn/tnet_turn.h175
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.c649
-rw-r--r--tinyNET/src/turn/tnet_turn_attribute.h196
-rw-r--r--tinyNET/src/turn/tnet_turn_message.c170
-rw-r--r--tinyNET/src/turn/tnet_turn_message.h75
87 files changed, 20144 insertions, 0 deletions
diff --git a/tinyNET/src/dhcp/tnet_dhcp.c b/tinyNET/src/dhcp/tnet_dhcp.c
new file mode 100644
index 0000000..8e7dbe6
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp.c
@@ -0,0 +1,338 @@
+/*
+* 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_dhcp.c
+ * @brief DHCP/BOOTP (RFC 2131 - Dynamic Host Configuration Protocol) utilities function for P-CSCF discovery(RFC 3319 and 3361).
+ * Also implement: RFC 3315, 3118, 3319, 3825 (Geoconf), 4676 (Civic Addresses Configuration Information) ...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_thread.h"
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+// Useful link: http://support.microsoft.com/?scid=kb%3Ben-us%3B169289&x=21&y=14
+// Another one: http://www.iana.org/assignments/bootp-dhcp-parameters/
+// Another one: http://www.slideshare.net/raini/DHCP-Presentation-v102
+// RFC 3319 Dynamic Host Configuration Protocol (DHCPv6) Options for Session Initiation Protocol (SIP) Servers
+// RFC 3361 Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for Session Initiation Protocol (SIP) Servers
+
+/**@defgroup tnet_dhcp_group DHCPv4/BOOTP (RFC 2131) implementation.
+*/
+
+/**@ingroup tnet_dhcp_group
+* Creates new DHCPv4 context.
+*/
+tnet_dhcp_ctx_t* tnet_dhcp_ctx_create()
+{
+ return tsk_object_new(tnet_dhcp_ctx_def_t);
+}
+
+/**@ingroup tnet_dhcp_group
+* Creates new DHCPv4 parameters.
+*/
+tnet_dhcp_params_t* tnet_dhcp_params_create()
+{
+ return tsk_object_new(tnet_dhcp_params_def_t);
+}
+
+/* FIXME: USE retransmission mech (*2*2...)
+*/
+/**@ingroup tnet_dhcp_group
+*/
+tnet_dhcp_reply_t* tnet_dhcp_send_request(tnet_dhcp_ctx_t* ctx, tnet_dhcp_request_t* request)
+{
+ tsk_buffer_t *output;
+ tnet_dhcp_reply_t* reply = tsk_null;
+ int ret;
+ struct timeval tv;
+ fd_set set;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_interface_t *iface;
+
+ tnet_socket_t *localsocket4 = tsk_null;
+ struct sockaddr_storage server;
+
+ if(!ctx || !request){
+ goto bail;
+ }
+
+ localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, ctx->port_client, tnet_socket_type_udp_ipv4);
+ if(!TNET_SOCKET_IS_VALID(localsocket4)){
+ TSK_DEBUG_ERROR("Failed to create/bind DHCP client socket.");
+ goto bail;
+ }
+
+ /* Always wait for 200ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (200 * 1000);
+
+ if(tnet_sockaddr_init("255.255.255.255", ctx->server_port, tnet_socket_type_udp_ipv4, &server)){
+ TNET_PRINT_LAST_ERROR("Failed to initialize the DHCP server address");
+ goto bail;
+ }
+
+ /* ENABLE BROADCASTING */
+ {
+#if defined(SOLARIS)
+ char yes = '1';
+#else
+ int yes = 1;
+#endif
+ if(setsockopt(localsocket4->fd, SOL_SOCKET, SO_BROADCAST, (char*)&yes, sizeof(int))){
+ TNET_PRINT_LAST_ERROR("Failed to enable broadcast option");
+ goto bail;
+ }
+ }
+
+ /* Set timeout */
+ timeout = tsk_time_epoch() + ctx->timeout;
+
+ do
+ {
+ /* RFC 2131 - 3.6 Use of DHCP in clients with multiple interfaces
+ A client with multiple network interfaces must use DHCP through each
+ interface independently to obtain configuration information
+ parameters for those separate interfaces.
+ */
+
+ tsk_list_foreach(item, ctx->interfaces){
+ iface = item->data;
+
+ /* Set FD */
+ FD_ZERO(&set);
+ FD_SET(localsocket4->fd, &set);
+
+ /* ciaddr */
+ if(request->type == dhcp_type_inform){
+ struct sockaddr_storage ss;
+ if(!tnet_get_sockaddr(localsocket4->fd, &ss)){
+ uint32_t addr = tnet_htonl_2(&((struct sockaddr_in*)&ss)->sin_addr);
+ memcpy(&request->ciaddr, &addr, 4);
+ }
+ }
+
+ /* chaddr */
+ memset(request->chaddr, 0, sizeof(request->chaddr));
+ request->hlen = iface->mac_address_length > sizeof(request->chaddr) ? sizeof(request->chaddr) : iface->mac_address_length;
+ memcpy(request->chaddr, iface->mac_address, request->hlen);
+
+ /* Serialize and send to the server. */
+ if(!(output = tnet_dhcp_message_serialize(ctx, request))){
+ TSK_DEBUG_ERROR("Failed to serialize the DHCP message.");
+ goto next_iface;
+ }
+ /* Send the request to the DHCP server */
+ if((ret =tnet_sockfd_sendto(localsocket4->fd, (const struct sockaddr*)&server, output->data, output->size))<0){
+ TNET_PRINT_LAST_ERROR("Failed to send DHCP request");
+
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ /* wait for response */
+ if((ret = select(localsocket4->fd+1, &set, NULL, NULL, &tv))<0){ /* Error */
+ TNET_PRINT_LAST_ERROR("select have failed.");
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ else if(ret == 0)
+ { /* timeout ==> do nothing */
+ }
+ else
+ { /* there is data to read */
+ tsk_size_t len = 0;
+ void* data = tsk_null;
+
+ /* Check how how many bytes are pending */
+ if((ret = tnet_ioctlt(localsocket4->fd, FIONREAD, &len))<0){
+ goto next_iface;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if((ret = tnet_sockfd_recv(localsocket4->fd, data, len, 0))<0){
+ TSK_FREE(data);
+
+ TNET_PRINT_LAST_ERROR("Failed to receive DHCP dgrams.");
+ goto next_iface;
+ }
+
+ /* Parse the incoming response. */
+ reply = tnet_dhcp_message_deserialize(ctx, data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if(reply)
+ { /* response successfuly parsed */
+ if(request->xid != reply->xid)
+ { /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(reply);
+ }
+ }
+ }
+
+ next_iface:
+ TSK_OBJECT_SAFE_FREE(output);
+ if(reply){
+ goto bail;
+ }
+ }
+ //break;//FIXME
+ }
+ while(timeout > tsk_time_epoch());
+
+bail:
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+
+ return reply;
+}
+
+/**@ingroup tnet_dhcp_group
+*/
+tnet_dhcp_reply_t* tnet_dhcp_query(tnet_dhcp_ctx_t* ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t* params)
+{
+ tnet_dhcp_reply_t* reply = tsk_null;
+ tnet_dhcp_request_t* request = tnet_dhcp_request_create();
+
+ if(!ctx || !params || !request){
+ goto bail;
+ }
+
+ request->type = type;
+ tnet_dhcp_message_add_codes(request, params->codes, params->codes_count);
+
+ reply = tnet_dhcp_send_request(ctx, request);
+
+bail:
+ TSK_OBJECT_SAFE_FREE(request);
+
+ return reply;
+}
+
+/**@ingroup tnet_dhcp_group
+*/
+int tnet_dhcp_params_add_code(tnet_dhcp_params_t* params, tnet_dhcp_option_code_t code)
+{
+ if(params){
+ if(params->codes_count < TNET_DHCP_MAX_CODES){
+ unsigned i;
+ for(i=0; i<params->codes_count; i++){
+ if(params->codes[i] == code){
+ return -3;
+ }
+ }
+ params->codes[params->codes_count++] = code;
+ }
+ else return -2;
+ }
+ return -1;
+}
+
+
+
+//=================================================================================================
+// [[DHCP CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dhcp_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_ctx_t *ctx = self;
+ if(ctx){
+ tnet_host_t host;
+
+ ctx->vendor_id = tsk_strdup(TNET_DHCP_VENDOR_ID_DEFAULT);
+ if(!tnet_gethostname(&host)){
+ ctx->hostname = tsk_strndup(host, tsk_strlen(host));
+ }
+ ctx->timeout = TNET_DHCP_TIMEOUT_DEFAULT;
+ ctx->max_msg_size = TNET_DHCP_MAX_MSG_SIZE;
+ ctx->port_client = TNET_DHCP_CLIENT_PORT;
+ ctx->server_port = TNET_DHCP_SERVER_PORT;
+ ctx->interfaces = tnet_get_interfaces();
+
+ if(!ctx->interfaces || TSK_LIST_IS_EMPTY(ctx->interfaces)){
+ TSK_DEBUG_ERROR("Failed to retrieve network interfaces.");
+ }
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_ctx_t *ctx = self;
+ if(ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_FREE(ctx->vendor_id);
+ TSK_FREE(ctx->hostname);
+
+ TSK_OBJECT_SAFE_FREE(ctx->interfaces);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_ctx_def_s =
+{
+ sizeof(tnet_dhcp_ctx_t),
+ tnet_dhcp_ctx_ctor,
+ tnet_dhcp_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_ctx_def_t = &tnet_dhcp_ctx_def_s;
+
+//=================================================================================================
+// [[DHCP PARAMS]] object definition
+//
+static tsk_object_t* tnet_dhcp_params_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_params_t *params = self;
+ if(params){
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_params_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_params_t *params = self;
+ if(params){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_params_def_s =
+{
+ sizeof(tnet_dhcp_params_t),
+ tnet_dhcp_params_ctor,
+ tnet_dhcp_params_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_params_def_t = &tnet_dhcp_params_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp.h b/tinyNET/src/dhcp/tnet_dhcp.h
new file mode 100644
index 0000000..6b306c5
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp.h
@@ -0,0 +1,121 @@
+/*
+* 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_dhcp.h
+ * @brief DHCP (RFC 2131 - Dynamic Host Configuration Protocol) utilities function for P-CSCF discovery(RFC 3319 and 3361)
+ * Also implement: RFC 3315, 3118, 3319, 3825 (Geoconf), 4676 (Civic Addresses Configuration Information)...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DHCP_H
+#define TNET_DHCP_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_safeobj.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_dhcp_group
+* Default timeout (in milliseconds) value for DHCP requests.
+*/
+#define TNET_DHCP_TIMEOUT_DEFAULT 2000
+
+/**@ingroup tnet_dhcp_group
+* Local port(client) to bind to for incoming DHCP messages as per RFC 2131 subclause 4.1. */
+#define TNET_DHCP_CLIENT_PORT 68
+/**@ingroup tnet_dhcp_group
+* Destination port(Server) for outgoing DHCP messages as per RFC 2131 subclause 4.1. */
+#define TNET_DHCP_SERVER_PORT 67
+
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_VENDOR_ID_DEFAULT
+*/
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_MAX_CODES
+*/
+/**@ingroup tnet_dhcp_group
+* @def TNET_DHCP_MAX_MSG_SIZE
+*/
+#define TNET_DHCP_VENDOR_ID_DEFAULT "doubango/v0.0.0"
+#define TNET_DHCP_MAX_CODES 20
+#define TNET_DHCP_MAX_MSG_SIZE 1500
+
+/**@ingroup tnet_dhcp_group
+* Parameter Request List (55)
+*/
+typedef struct tnet_dhcp_params_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_dhcp_option_code_t codes[TNET_DHCP_MAX_CODES];
+ unsigned codes_count;
+}
+tnet_dhcp_params_t;
+
+/**@ingroup tnet_dhcp_group
+*/
+typedef struct tnet_dhcp_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* vendor_id;
+ char* hostname;
+ uint16_t max_msg_size; /**< Option code 57. */
+
+ uint64_t timeout;
+
+ tnet_port_t port_client; /**< Local port to bind to for incloming DHCP messages. Default: 68 */
+ tnet_port_t server_port; /**< Destination port for outgoing DHCP messages. Default: 64 */
+ tnet_interfaces_L_t *interfaces;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dhcp_ctx_t;
+
+
+TINYNET_API tnet_dhcp_reply_t* tnet_dhcp_query(tnet_dhcp_ctx_t* ctx, tnet_dhcp_message_type_t type, tnet_dhcp_params_t* params);
+#define tnet_dhcp_query_discover(ctx, params) tnet_dhcp_query(ctx, dhcp_type_discover, params)
+#define tnet_dhcp_query_request(ctx, params) tnet_dhcp_query(ctx, dhcp_type_request, params)
+#define tnet_dhcp_query_decline(ctx, params) tnet_dhcp_query(ctx, dhcp_type_decline, params)
+#define tnet_dhcp_query_release(ctx, params) tnet_dhcp_query(ctx, dhcp_type_release, params)
+#define tnet_dhcp_query_inform(ctx, params) tnet_dhcp_query(ctx, dhcp_type_inform, params)
+
+TINYNET_API int tnet_dhcp_params_add_code(tnet_dhcp_params_t* params, tnet_dhcp_option_code_t code);
+
+
+TINYNET_API tnet_dhcp_ctx_t* tnet_dhcp_ctx_create();
+TINYNET_API tnet_dhcp_params_t* tnet_dhcp_params_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_ctx_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_params_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_message.c b/tinyNET/src/dhcp/tnet_dhcp_message.c
new file mode 100644
index 0000000..e4eff3b
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_message.c
@@ -0,0 +1,355 @@
+/*
+* 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_dhcp_message.c
+ * @brief DHCP Message as per RFC 2131 subclause 2.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp_message.h"
+#include "tnet_dhcp.h"
+
+#include "../tnet_utils.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_time.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+tnet_dhcp_message_t* tnet_dhcp_message_create(tnet_dhcp_message_op_t opcode)
+{
+ return tsk_object_new(tnet_dhcp_message_def_t, opcode);
+}
+
+tnet_dhcp_request_t* tnet_dhcp_request_create()
+{
+ return tnet_dhcp_message_create(dhcp_op_bootrequest);
+}
+
+tnet_dhcp_message_t* tnet_dhcp_reply_create()
+{
+ return tnet_dhcp_message_create(dhcp_op_bootreply);
+}
+
+tsk_buffer_t* tnet_dhcp_message_serialize(const tnet_dhcp_ctx_t *ctx, const tnet_dhcp_message_t *message)
+{
+ tsk_buffer_t* output = 0;
+ uint8_t _1byte;
+ uint16_t _2bytes;
+ uint32_t _4bytes;
+
+ /* Check message validity */
+ if(!message){
+ goto bail;
+ }
+
+ output = tsk_buffer_create_null();
+
+ /*== OP HTYPE HLEN HOPS */
+ _4bytes = (((uint32_t)(message->op)) << 24) |
+ (((uint32_t)(message->htype)) << 16) |
+ (((uint16_t)(message->hlen)) << 8) | message->hops;
+ _4bytes = tnet_ntohl(_4bytes);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== XID */
+ _4bytes = tnet_ntohl(message->xid);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== SECS */
+ _2bytes = tnet_ntohs(message->secs);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /*== FLAGS */
+ _2bytes = tnet_ntohs(message->flags);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /*== CIADDR */
+ _4bytes = tnet_ntohl(message->ciaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== YIADDR */
+ _4bytes = tnet_ntohl(message->yiaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== SIADDR */
+ _4bytes = tnet_ntohl(message->siaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== GIADDR */
+ _4bytes = tnet_ntohl(message->giaddr);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ /*== CHADDR */
+ tsk_buffer_append(output, message->chaddr, sizeof(message->chaddr));
+ /*== sname (unused) */
+ tsk_buffer_append(output, message->sname, sizeof(message->sname));
+ /*== file (unused) */
+ tsk_buffer_append(output, message->file, sizeof(message->file));
+ /*== Magic Cookie */
+ _4bytes = tnet_ntohl(TNET_DHCP_MAGIC_COOKIE);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== Message Type (option 53)
+ */
+ tnet_dhcp_option_serializeex(dhcp_code_DHCP_Msg_Type, 1, &message->type, output);
+
+ /*== Client Identifier (option 61) ==> RFC 2132 - 9.14. Client-identifier
+ Code Len Type Client-Identifier
+ +-----+-----+-----+-----+-----+---
+ | 61 | n | t1 | i1 | i2 | ...
+ +-----+-----+-----+-----+-----+---
+ */
+ if(message->hlen){
+ uint8_t client_id[17]; // 16 /*sizeof(chaddr)*/+ 1/*htype*/
+ /*if(client_id)*/{
+ client_id[0] = message->htype;
+ memcpy(&client_id[1], message->chaddr, message->hlen);
+ tnet_dhcp_option_serializeex(dhcp_code_Client_Id, (message->hlen+1), client_id, output);
+ }
+ }
+ /*== Host name(10) ==> RFC 2132 - 3.14. Host Name Option
+ Code Len Host Name
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 12 | n | h1 | h2 | h3 | h4 | h5 | h6 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ if(TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->hostname){
+ tnet_dhcp_option_serializeex(dhcp_code_Hostname, tsk_strlen(ctx->hostname), ctx->hostname, output);
+ }
+ /*== Vendor classId(60) ==> RFC 2132 - 9.13. Vendor class identifier
+ Code Len Vendor class Identifier
+ +-----+-----+-----+-----+---
+ | 60 | n | i1 | i2 | ...
+ +-----+-----+-----+-----+---
+ */
+ if(TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->vendor_id){
+ tnet_dhcp_option_serializeex(dhcp_code_Class_Id, tsk_strlen(ctx->vendor_id), ctx->vendor_id, output);
+ }
+
+ /*== RFC 2132 - 9.10. Maximum DHCP Message Size (57)
+ Code Len Length
+ +-----+-----+-----+-----+
+ | 57 | 2 | l1 | l2 |
+ +-----+-----+-----+-----+
+ */
+ if(TNET_DHCP_MESSAGE_IS_REQUEST(message) && ctx->max_msg_size){
+ _2bytes = tnet_ntohs(ctx->max_msg_size);
+ tnet_dhcp_option_serializeex(dhcp_code_DHCP_Max_Msg_Size, 2, &_2bytes, output);
+ }
+
+ /*== DHCP Options
+ */
+ {
+ tsk_list_item_t *item;
+ tnet_dhcp_option_t* option;
+ tsk_list_foreach(item, message->options)
+ {
+ option = (tnet_dhcp_option_t*)item->data;
+ if(tnet_dhcp_option_serialize(option, output)){
+ TSK_DEBUG_WARN("Failed to serialize DHCP OPTION (%u)", option->code);
+ }
+ }
+ }
+
+ /* RFC 2131 - 4.1 Constructing and sending DHCP messages
+ The last option must always be the 'end' option.
+ */
+ _1byte = dhcp_code_End;
+ tsk_buffer_append(output, &(_1byte), 1);
+
+bail:
+ return output;
+}
+
+tnet_dhcp_message_t* tnet_dhcp_message_deserialize(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size)
+{
+ tnet_dhcp_message_t *message = 0;
+ uint8_t *dataPtr, *dataEnd, *dataStart;
+
+ if(!data || !size)
+ {
+ goto bail;
+ }
+
+ if(size < TNET_DHCP_MESSAGE_MIN_SIZE){
+ TSK_DEBUG_ERROR("DHCP message too short.");
+ goto bail;
+ }
+
+ if(!(message = tnet_dhcp_reply_create())){ /* If REQUEST OP will be overridedden */
+ TSK_DEBUG_ERROR("Failed to create new DHCP message.");
+ goto bail;
+ }
+
+ dataPtr = (uint8_t*)data;
+ dataStart = dataPtr;
+ dataEnd = (dataStart + size);
+
+ /*== op (1)*/
+ message->op = *(dataPtr++);
+ /*== htype (1) */
+ message->htype = *(dataPtr++);
+ /*== hlen (1) */
+ message->hlen = *(dataPtr++);
+ /*== htype (1) */
+ message->hops = *(dataPtr++);
+ /*== xid (4) */
+ message->xid= tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== secs (2) */
+ message->secs = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /*== flags (2) */
+ message->flags = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /*== ciaddr (4) */
+ message->ciaddr= tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== yiaddr (4) */
+ message->yiaddr= tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== siaddr (4) */
+ message->siaddr= tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== giaddr (4) */
+ message->giaddr= tnet_htonl_2(dataPtr);
+ dataPtr += 4;
+ /*== chaddr (16[max]) */
+ memcpy(message->chaddr, dataPtr, message->hlen>16 ? 16 : message->hlen);
+ dataPtr += 16;
+ /*== sname (64) */
+ memcpy(message->sname, dataPtr, 64);
+ dataPtr += 64;
+ /*== file (128) */
+ memcpy(message->file, dataPtr, 128);
+ dataPtr += 128;
+ /*== Magic Cookie (4) */
+ if(tnet_htonl_2(dataPtr) != TNET_DHCP_MAGIC_COOKIE){
+ TSK_DEBUG_ERROR("Invalid DHCP magic cookie.");
+ // Do not exit ==> continue parsing.
+ }
+ dataPtr += 4;
+
+ /*== options (variable) */
+ while(dataPtr<dataEnd && *dataPtr!=dhcp_code_End)
+ {
+ tnet_dhcp_option_t* option = tnet_dhcp_option_deserialize(dataPtr, (dataEnd-dataPtr));
+ if(option && option->value){
+
+ if(option->code == dhcp_code_DHCP_Msg_Type){
+ message->type = (tnet_dhcp_message_type_t)*TSK_BUFFER_TO_U8(option->value);
+ }
+
+ dataPtr += option->value->size + 2/*Code Len*/;
+ tsk_list_push_back_data(message->options, (void**)&option);
+ }
+ else break;
+ }
+
+bail:
+ return message;
+}
+
+
+const tnet_dhcp_option_t* tnet_dhcp_message_find_option(const tnet_dhcp_message_t *message, tnet_dhcp_option_code_t code)
+{
+ tsk_list_item_t *item;
+
+ if(!message){
+ goto bail;
+ }
+
+ tsk_list_foreach(item, message->options)
+ {
+ if(((tnet_dhcp_option_t*)item->data)->code == code){
+ return ((tnet_dhcp_option_t*)item->data);
+ }
+ }
+
+bail:
+ return 0;
+}
+
+int tnet_dhcp_message_add_codes(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count)
+{
+ int ret = -1;
+
+ if(!self){
+ goto bail;
+ }
+ if(codes_count){
+ unsigned i;
+
+ tnet_dhcp_option_paramslist_t* option = (tnet_dhcp_option_paramslist_t*)tnet_dhcp_message_find_option(self, dhcp_code_Parameter_List);
+ if(!option){
+ tnet_dhcp_option_paramslist_t *option_paramslist = tnet_dhcp_option_paramslist_create();
+ option = option_paramslist;
+ tsk_list_push_back_data(self->options, (void**)&option_paramslist);
+ }
+
+ for(i=0; i<codes_count; i++){
+ if((ret = tnet_dhcp_option_paramslist_add_code(option, codes[i]))){
+ break;
+ }
+ }
+ }
+
+bail:
+ return ret;
+}
+
+
+//=================================================================================================
+// [[DHCP MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dhcp_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_message_t *message = self;
+ if(message){
+ static uint32_t __dhcpmessage_unique_xid = 0;//(uint32_t)tsk_time_epoch();
+
+ message->op = va_arg(*app, tnet_dhcp_message_op_t);
+ message->htype = tnet_htype_Ethernet_10Mb;
+ message->hlen = 0x06;
+
+ message->xid = ++(__dhcpmessage_unique_xid);
+ message->options = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_message_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_message_t *message = self;
+ if(message){
+ TSK_OBJECT_SAFE_FREE(message->options);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_message_def_s =
+{
+ sizeof(tnet_dhcp_message_t),
+ tnet_dhcp_message_ctor,
+ tnet_dhcp_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_message_def_t = &tnet_dhcp_message_def_s;
+
diff --git a/tinyNET/src/dhcp/tnet_dhcp_message.h b/tinyNET/src/dhcp/tnet_dhcp_message.h
new file mode 100644
index 0000000..4101e9b
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_message.h
@@ -0,0 +1,226 @@
+/*
+* 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_dhcp_message.h
+ * @brief DHCP Message as per RFC 2131 subclause 2.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DHCP_MESSAGE_H
+#define TNET_DHCP_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_option.h"
+#include "tnet_hardwares.h"
+
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_dhcp_ctx_s;
+
+#define TNET_DHCP_MESSAGE_IS_REQUEST(self) ((self) && ((self)->op==dhcp_op_bootrequest))
+#define TNET_DHCP_MESSAGE_IS_REPLY(self) ((self) && ((self)->op==dhcp_op_bootreply))
+
+#define TNET_DHCP_MAGIC_COOKIE 0x63825363 /**< DHCP magic cookie (99, 130, 83 and 99 in decimal).*/
+
+#define TNET_DHCP_MESSAGE_MIN_SIZE 223 /* Is it rigth? */
+
+/** List of all supported DHCP message (see RFC 2131).
+*/
+typedef enum tnet_dhcp_message_type_e
+{
+ /**< DHCPDISCOVER - Client broadcast to locate available servers.
+ */
+ dhcp_type_discover = 1,
+
+ /**< DHCPOFFER - Server to client in response to DHCPDISCOVER with
+ offer of configuration parameters.
+ */
+ dhcp_type_offer = 2,
+
+ /**< DHCPREQUEST - Client message to servers either (a) requesting
+ offered parameters from one server and implicitly
+ declining offers from all others, (b) confirming
+ correctness of previously allocated address after,
+ e.g., system reboot, or (c) extending the lease on a
+ particular network address.
+ */
+ dhcp_type_request = 3,
+
+ /**< DHCPDECLINE - Client to server indicating network address is already
+ in use.
+ */
+ dhcp_type_decline = 4,
+
+ /**< DHCPACK - Server to client with configuration parameters,
+ including committed network address.
+ */
+ dhcp_type_ack = 5,
+
+ /**< DHCPNAK - Server to client indicating client's notion of network
+ address is incorrect (e.g., client has moved to new
+ subnet) or client's lease as expired
+ */
+ dhcp_type_nack = 6,
+
+ /**< DHCPRELEASE - Client to server relinquishing network address and
+ cancelling remaining lease.
+ */
+ dhcp_type_release = 7,
+
+ /**< DHCPINFORM - Client to server, asking only for local configuration
+ parameters; client already has externally configured
+ network address.
+ */
+ dhcp_type_inform = 8,
+}
+tnet_dhcp_message_type_t;
+
+/** DHCP message OP code / message type.
+*/
+typedef enum tnet_dhcp_message_op_e
+{
+ dhcp_op_bootrequest = 1,
+ dhcp_op_bootreply = 2
+}
+tnet_dhcp_message_op_t;
+
+/** BOOTP/DHCP message as per RFC 2131 subclause 2.
+*/
+typedef struct tnet_dhcp_message_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /**< DHCP message type. Mandatory.
+ */
+ tnet_dhcp_message_type_t type;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | op (1) | htype (1) | hlen (1) | hops (1) |
+ +---------------+---------------+---------------+---------------+
+ | xid (4) |
+ +-------------------------------+-------------------------------+
+ | secs (2) | flags (2) |
+ +-------------------------------+-------------------------------+
+ | ciaddr (4) |
+ +---------------------------------------------------------------+
+ | yiaddr (4) |
+ +---------------------------------------------------------------+
+ | siaddr (4) |
+ +---------------------------------------------------------------+
+ | giaddr (4) |
+ +---------------------------------------------------------------+
+ | |
+ | chaddr (16) |
+ | |
+ | |
+ +---------------------------------------------------------------+
+ | |
+ | sname (64) |
+ +---------------------------------------------------------------+
+ | |
+ | file (128) |
+ +---------------------------------------------------------------+
+ | |
+ | options (variable) |
+ +---------------------------------------------------------------+
+ */
+
+ /**< Message op code / message type (1-byte).
+ 1 = BOOTREQUEST, 2 = BOOTREPLY
+ */
+ tnet_dhcp_message_op_t op;
+ /**< Hardware address type, see ARP section in "Assigned Numbers" RFC; e.g., '1' = 10mb ethernet.
+ For more information see RFC 1340.
+ */
+ tnet_hardware_type_t htype;
+ /**< Hardware address length (e.g. '6' for 10mb ethernet). tsk_strlen(chaddr).
+ */
+ uint8_t hlen;
+ /**< Client sets to zero, optionally used by relay agents when booting via a relay agent.
+ */
+ uint8_t hops;
+ /**< Transaction ID, a random number chosen by the client, used by the client
+ and server to associate messages and responses between a client and a server.
+ */
+ uint32_t xid;
+ /**< Filled in by client, seconds elapsed since client began address acquisition or renewal process.
+ */
+ uint16_t secs;
+ /**< Flags (see figure 2)
+ */
+ uint16_t flags;
+ /**< Client IP address; only filled in if client is in BOUND, RENEW or REBINDING
+ state and can respond to ARP requests.
+ */
+ uint32_t ciaddr;
+ /**< 'your' (client) IP address.
+ */
+ uint32_t yiaddr;
+ /**< IP address of next server to use in bootstrap;
+ returned in DHCPOFFER, DHCPACK by server.
+ */
+ uint32_t siaddr;
+ /**< Relay agent IP address, used in booting via a relay agent.
+ */
+ uint32_t giaddr;
+ /**< Client hardware address.
+ */
+ uint8_t chaddr[16];
+ /**< Optional server host name, null terminated string.
+ */
+ uint8_t sname[64];
+ /**<Boot file name, null terminated string; "generic" name or null in DHCPDISCOVER,
+ fully qualifieddirectory-path name in DHCPOFFER.
+ */
+ uint8_t file[128];
+ /**Optional parameters field. See the options documents for a list of defined options.
+ For more information please refer to RFC 2132, 1497 and 1533.
+ */
+ tnet_dhcp_options_L_t *options;
+}
+tnet_dhcp_message_t;
+
+typedef tsk_list_t tnet_dhcp_messages_L_t;
+typedef tnet_dhcp_message_t tnet_dhcp_request_t; /**< BOOTREQUEST message. */
+typedef tnet_dhcp_message_t tnet_dhcp_reply_t; /**< BOOTREPLY message. */
+
+tsk_buffer_t* tnet_dhcp_message_serialize(const struct tnet_dhcp_ctx_s *ctx, const tnet_dhcp_message_t *self);
+tnet_dhcp_message_t* tnet_dhcp_message_deserialize(const struct tnet_dhcp_ctx_s *ctx, const uint8_t *data, tsk_size_t size);
+const tnet_dhcp_option_t* tnet_dhcp_message_find_option(const tnet_dhcp_message_t *self, tnet_dhcp_option_code_t code);
+int tnet_dhcp_message_add_codes(tnet_dhcp_message_t *self, tnet_dhcp_option_code_t codes[], unsigned codes_count);
+
+TINYNET_API tnet_dhcp_message_t* tnet_dhcp_message_create(tnet_dhcp_message_op_t opcode);
+TINYNET_API tnet_dhcp_request_t* tnet_dhcp_request_create();
+TINYNET_API tnet_dhcp_message_t* tnet_dhcp_reply_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_message_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_MESSAGE_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option.c b/tinyNET/src/dhcp/tnet_dhcp_option.c
new file mode 100644
index 0000000..39a28e9
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option.c
@@ -0,0 +1,326 @@
+/*
+* 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_dhcp_option.c
+ * @brief DHCP Options and BOOTP Vendor Extensions as per RFC 2132.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp_option.h"
+
+#include "tnet_dhcp_option_sip.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+tnet_dhcp_option_t* tnet_dhcp_option_create(tnet_dhcp_option_code_t code)
+{
+ return tsk_object_new(tnet_dhcp_option_def_t, code);
+}
+
+tnet_dhcp_option_paramslist_t* tnet_dhcp_option_paramslist_create()
+{
+ return tsk_object_new(tnet_dhcp_option_paramslist_def_t);
+}
+
+tnet_dhcp_option_dns_t* tnet_dhcp_option_dns_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp_option_dns_def_t, payload, payload_size);
+}
+
+/** Initializes DHCPv4 option.
+ *
+ * @param [in,out] self The option to initialize.
+ * @param code The code of the option to initialize.
+ *
+ * @return Zero if succeed and non-zero error code otherwise.
+**/
+int tnet_dhcp_option_init(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code)
+{
+ if(self)
+ {
+ if(!self->initialized)
+ {
+ self->code = code;
+ //option->value = tsk_buffer_create_null();
+
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+int tnet_dhcp_option_deinit(tnet_dhcp_option_t *self)
+{
+ if(self)
+ {
+ if(self->initialized)
+ {
+ TSK_OBJECT_SAFE_FREE(self->value);
+
+ self->initialized = tsk_false;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+tnet_dhcp_option_t* tnet_dhcp_option_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp_option_t *option = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp_option_code_t code;
+ uint8_t len;
+
+ /* Check validity */
+ if(!dataPtr || size<2/*Code Len*/){
+ goto bail;
+ }
+
+ code = (tnet_dhcp_option_code_t)*dataPtr++;
+ len = *dataPtr++;
+
+ switch(code)
+ {
+ case dhcp_code_SIP_Servers_DHCP_Option:
+ {
+ option = (tnet_dhcp_option_t *)tnet_dhcp_option_sip_create(dataPtr, len);
+ break;
+ }
+
+ case dhcp_code_Domain_Server:
+ {
+ option = (tnet_dhcp_option_t *)tnet_dhcp_option_dns_create(dataPtr, len);
+ break;
+ }
+
+ default:
+ {
+ option = tnet_dhcp_option_create(code);
+ }
+ }
+
+ /* In all case */
+ if(option && !option->value && len){
+ option->value = tsk_buffer_create((((uint8_t*)data) + 2/*Code Len*/), len);
+ }
+
+bail:
+ return option;
+}
+
+int tnet_dhcp_option_serialize(const tnet_dhcp_option_t* self, tsk_buffer_t *output)
+{
+ if(!self || !output){
+ return -1;
+ }
+
+ /* Code */
+ tsk_buffer_append(output, &(self->code), 1);
+
+ if(self->value){
+ /* Length */
+ tsk_buffer_append(output, &(self->value->size), 1);
+
+ /* Value */
+ tsk_buffer_append(output, self->value->data, self->value->size);
+ }
+ else{
+ /* Length */
+ static uint8_t zero = 0x00;
+ tsk_buffer_append(output, &zero, 1);
+ }
+
+ return 0;
+}
+
+int tnet_dhcp_option_serializeex(tnet_dhcp_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output)
+{
+ if(value && length && output){
+ tsk_buffer_append(output, &(code), 1);
+ tsk_buffer_append(output, &(length), 1);
+ tsk_buffer_append(output, value, length);
+
+ return 0;
+ }
+ return -1;
+}
+
+//
+// [[DHCP OPTION]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_t *option = self;
+ if(option){
+ tnet_dhcp_option_init(option, va_arg(*app, tnet_dhcp_option_code_t));
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_t *option = self;
+ if(option){
+ tnet_dhcp_option_deinit(option);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_def_s =
+{
+ sizeof(tnet_dhcp_option_t),
+ tnet_dhcp_option_ctor,
+ tnet_dhcp_option_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_def_t = &tnet_dhcp_option_def_s;
+
+
+
+/*=======================================================================================
+* RFC 2132 - 9.8. Parameter Request List
+*=======================================================================================*/
+int tnet_dhcp_option_paramslist_add_code(tnet_dhcp_option_paramslist_t* self, tnet_dhcp_option_code_t code)
+{
+ if(self){
+ if(!TNET_DHCP_OPTION(self)->value){
+ TNET_DHCP_OPTION(self)->value = tsk_buffer_create_null();
+ }
+ return tsk_buffer_append(TNET_DHCP_OPTION(self)->value, &code, 1);
+ }
+ return -1;
+}
+
+//
+// [[DHCP OPTION - RFC 2132 9.8. Parameter Request List]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_paramslist_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_paramslist_t *option = self;
+ if(option){
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_Parameter_List);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_paramslist_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_paramslist_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_paramslist_def_s =
+{
+ sizeof(tnet_dhcp_option_paramslist_t),
+ tnet_dhcp_option_paramslist_ctor,
+ tnet_dhcp_option_paramslist_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_paramslist_def_t = &tnet_dhcp_option_paramslist_def_s;
+
+
+/*=======================================================================================
+* RFC 2132 - 3.8. Domain Name Server Option
+*=======================================================================================*/
+//
+// [[DHCP OPTION - RFC 2132 3.8. Domain Name Server Option]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_dns_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_dns_t *option = self;
+ if(option){
+ 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;
+ const uint8_t* payloadEnd = (payloadPtr + payload_size);
+
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_Domain_Server);
+
+ option->servers = tsk_list_create();
+
+ if(payload_size<4 || payload_size%4){
+ TSK_DEBUG_ERROR("DHCP - The minimum length for this option is 4 octets, and the length MUST always be a multiple of 4.");
+ }
+ else{
+ tsk_size_t i;
+ char* ip4 = 0;
+ uint32_t address;
+ tsk_string_t* addrstring;
+
+ for(i=0; i<payload_size && (payloadPtr< payloadEnd); i+=4){
+ /*
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ address = tnet_htonl_2(payloadPtr);
+ tsk_sprintf(&ip4, "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+
+ addrstring = tsk_string_create(ip4);
+ tsk_list_push_back_data(option->servers, (void*)&addrstring);
+
+ TSK_FREE(ip4);
+ payloadPtr+= 4;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_dns_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_dns_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+
+ TSK_OBJECT_SAFE_FREE(option->servers);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_dns_def_s =
+{
+ sizeof(tnet_dhcp_option_dns_t),
+ tnet_dhcp_option_dns_ctor,
+ tnet_dhcp_option_dns_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_dns_def_t = &tnet_dhcp_option_dns_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option.h b/tinyNET/src/dhcp/tnet_dhcp_option.h
new file mode 100644
index 0000000..b9c313e
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option.h
@@ -0,0 +1,291 @@
+/*
+* 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_dhcp_option.h
+ * @brief DHCP Options and BOOTP Vendor Extensions as per RFC 2132.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DHCP_OPTION_H
+#define TNET_DHCP_OPTION_H
+
+#include "tinynet_config.h"
+
+#include "tsk_buffer.h"
+#include "tsk_string.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP_OPTION(self) ((tnet_dhcp_option_t*)(self))
+
+typedef enum tnet_dhcp_option_code_e
+{
+ dhcp_code_Pad= 0 ,/**< Pad 0 None [RFC2132] */
+ dhcp_code_Subnet_Mask= 1 ,/**< Subnet Mask 4 Subnet Mask Value [RFC2132] */
+ dhcp_code_Time_Offset= 2 ,/**< Time Offset 4 Time Offset in Seconds from UTC [RFC2132] (note: deprecated by 100 and 101) */
+ dhcp_code_Router= 3 ,/**< Router N N/4 Router addresses [RFC2132] */
+ dhcp_code_Time_Server= 4 ,/**< Time Server N N/4 Timeserver addresses [RFC2132] */
+ dhcp_code_Name_Server= 5 ,/**< Name Server N N/4 IEN-116 Server addresses [RFC2132] */
+ dhcp_code_Domain_Server= 6 ,/**< Domain Server N N/4 DNS Server addresses [RFC2132] */
+ dhcp_code_Log_Server= 7 ,/**< Log Server N N/4 Logging Server addresses [RFC2132] */
+ dhcp_code_Quotes_Server= 8 ,/**< Quotes Server N N/4 Quotes Server addresses [RFC2132] */
+ dhcp_code_LPR_Server= 9 ,/**< LPR Server N N/4 Printer Server addresses [RFC2132] */
+ dhcp_code_Impress_Server= 10 ,/**< Impress Server N N/4 Impress Server addresses [RFC2132] */
+ dhcp_code_RLP_Server= 11 ,/**< RLP Server N N/4 RLP Server addresses [RFC2132] */
+ dhcp_code_Hostname= 12 ,/**< Hostname N Hostname string [RFC2132] */
+ dhcp_code_Boot_File_Size= 13 ,/**< Boot File Size 2 Size of boot file in 512 byte chunks [RFC2132] */
+ dhcp_code_Merit_Dump_File= 14 ,/**< Merit Dump File N Client to dump and name the file to dump it to [RFC2132] */
+ dhcp_code_Domain_Name= 15 ,/**< Domain Name N The DNS domain name of the client [RFC2132] */
+ dhcp_code_Swap_Server= 16 ,/**< Swap Server N Swap Server address [RFC2132] */
+ dhcp_code_Root_Path= 17 ,/**< Root Path N Path name for root disk [RFC2132] */
+ dhcp_code_Extension_File= 18 ,/**< Extension File N Path name for more BOOTP info [RFC2132] */
+ dhcp_code_Forward_On_Off= 19 ,/**< Forward On/Off 1 Enable/Disable IP Forwarding [RFC2132] */
+ dhcp_code_SrcRte_On_Off = 20 ,/**< SrcRte On/Off 1 Enable/Disable Source Routing [RFC2132] */
+ dhcp_code_Policy_Filter= 21 ,/**< Policy Filter N Routing Policy Filters [RFC2132] */
+ dhcp_code_Max_DG_Assembly= 22 ,/**< Max DG Assembly 2 Max Datagram Reassembly Size [RFC2132] */
+ dhcp_code_Default_IP_TTL= 23 ,/**< Default IP TTL 1 Default IP Time to Live [RFC2132] */
+ dhcp_code_MTU_Timeout= 24 ,/**< MTU Timeout 4 Path MTU Aging Timeout [RFC2132] */
+ dhcp_code_MTU_Plateau= 25 ,/**< MTU Plateau N Path MTU Plateau Table [RFC2132] */
+ dhcp_code_MTU_Interface= 26 ,/**< MTU Interface 2 Interface MTU Size [RFC2132] */
+ dhcp_code_MTU_Subnet= 27 ,/**< MTU Subnet 1 All Subnets are Local [RFC2132] */
+ dhcp_code_Broadcast_Address= 28 ,/**< Broadcast Address 4 Broadcast Address [RFC2132] */
+ dhcp_code_Mask_Discovery= 29 ,/**< Mask Discovery 1 Perform Mask Discovery [RFC2132] */
+ dhcp_code_Mask_Supplier= 30 ,/**< Mask Supplier 1 Provide Mask to Others [RFC2132] */
+ dhcp_code_Router_Discovery= 31 ,/**< Router Discovery 1 Perform Router Discovery [RFC2132] */
+ dhcp_code_Router_Request= 32 ,/**< Router Request 4 Router Solicitation Address [RFC2132] */
+ dhcp_code_Static_Route= 33 ,/**< Static Route N Static Routing Table [RFC2132] */
+ dhcp_code_Trailers= 34 ,/**< Trailers 1 Trailer Encapsulation [RFC2132] */
+ dhcp_code_ARP_Timeout= 35 ,/**< ARP Timeout 4 ARP Cache Timeout [RFC2132] */
+ dhcp_code_Ethernet= 36 ,/**< Ethernet 1 Ethernet Encapsulation [RFC2132] */
+ dhcp_code_Default_TCP_TTL= 37 ,/**< Default TCP TTL 1 Default TCP Time to Live [RFC2132] */
+ dhcp_code_Keepalive_Time= 38 ,/**< Keepalive Time 4 TCP Keepalive Interval [RFC2132] */
+ dhcp_code_Keepalive_Data= 39 ,/**< Keepalive Data 1 TCP Keepalive Garbage [RFC2132] */
+ dhcp_code_NIS_Domain= 40 ,/**< NIS Domain N NIS Domain Name [RFC2132] */
+ dhcp_code_NIS_Servers= 41 ,/**< NIS Servers N NIS Server Addresses [RFC2132] */
+ dhcp_code_NTP_Servers= 42 ,/**< NTP Servers N NTP Server Addresses [RFC2132] */
+ dhcp_code_Vendor_Specific= 43 ,/**< Vendor Specific N Vendor Specific Information [RFC2132] */
+ dhcp_code_NETBIOS_Name_Srv= 44 ,/**< NETBIOS Name Srv N NETBIOS Name Servers [RFC2132] */
+ dhcp_code_NETBIOS_Dist_Srv= 45 ,/**< NETBIOS Dist Srv N NETBIOS Datagram Distribution [RFC2132] */
+ dhcp_code_NETBIOS_Node_Type= 46 ,/**< NETBIOS Node Type 1 NETBIOS Node Type [RFC2132] */
+ dhcp_code_NETBIOS_Scope= 47 ,/**< NETBIOS Scope N NETBIOS Scope [RFC2132] */
+ dhcp_code_X_Window_Font= 48 ,/**< X Window Font N X Window Font Server [RFC2132] */
+ dhcp_code_X_Window_Manager= 49 ,/**< X Window Manager N X Window Display Manager [RFC2132] */
+ dhcp_code_Address_Request= 50 ,/**< Address Request 4 Requested IP Address [RFC2132] */
+ dhcp_code_Address_Time= 51 ,/**< Address Time 4 IP Address Lease Time [RFC2132] */
+ dhcp_code_Overload= 52 ,/**< Overload 1 Overload "sname" or "file" [RFC2132] */
+ dhcp_code_DHCP_Msg_Type= 53 ,/**< DHCP Msg Type 1 DHCP Message Type [RFC2132] */
+ dhcp_code_DHCP_Server_Id= 54 ,/**< DHCP Server Id 4 DHCP Server Identification [RFC2132] */
+ dhcp_code_Parameter_List= 55 ,/**< Parameter List N Parameter Request List [RFC2132] */
+ dhcp_code_DHCP_Error_Message= 56 ,/**< DHCP Message N DHCP Error Message [RFC2132] */
+ dhcp_code_DHCP_Max_Msg_Size= 57 ,/**< DHCP Max Msg Size 2 DHCP Maximum Message Size [RFC2132] */
+ dhcp_code_Renewal_Time= 58 ,/**< Renewal Time 4 DHCP Renewal (T1) Time [RFC2132] */
+ dhcp_code_Rebinding_Time= 59 ,/**< Rebinding Time 4 DHCP Rebinding (T2) Time [RFC2132] */
+ dhcp_code_Class_Id= 60 ,/**< Class Id N Class Identifier [RFC2132] */
+ dhcp_code_Client_Id= 61 ,/**< Client Id N Client Identifier [RFC2132] */
+ dhcp_code_NetWare_IP_Domain= 62 ,/**< NetWare/IP Domain N NetWare/IP Domain Name [RFC2242] */
+ dhcp_code_NetWare_IP_Option= 63 ,/**< NetWare/IP Option N NetWare/IP sub Options [RFC2242] */
+ dhcp_code_NIS_Domain_Name= 64 ,/**< NIS-Domain-Name N NIS+ v3 Client Domain Name [RFC2132] */
+ dhcp_code_NIS_Server_Addr = 65 ,/**< NIS-Server-Addr N NIS+ v3 Server Addresses [RFC2132] */
+ dhcp_code_Server_Name= 66 ,/**< Server-Name N TFTP Server Name [RFC2132] */
+ dhcp_code_Bootfile_Name= 67 ,/**< Bootfile-Name N Boot File Name [RFC2132] */
+ dhcp_code_Home_Agent_Addrs= 68 ,/**< Home-Agent-Addrs N Home Agent Addresses [RFC2132] */
+ dhcp_code_SMTP_Server= 69 ,/**< SMTP-Server N Simple Mail Server Addresses [RFC2132] */
+ dhcp_code_POP3_Server= 70 ,/**< POP3-Server N Post Office Server Addresses [RFC2132] */
+ dhcp_code_NNTP_Server= 71 ,/**< NNTP-Server N Network News Server Addresses [RFC2132] */
+ dhcp_code_WWW_Server= 72 ,/**< WWW-Server N WWW Server Addresses [RFC2132] */
+ dhcp_code_Finger_Server= 73 ,/**< Finger-Server N Finger Server Addresses [RFC2132] */
+ dhcp_code_IRC_Server= 74 ,/**< IRC-Server N Chat Server Addresses [RFC2132] */
+ dhcp_code_StreetTalk_Server= 75 ,/**< StreetTalk-Server N StreetTalk Server Addresses [RFC2132] */
+ dhcp_code_STDA_Server= 76 ,/**< STDA-Server N ST Directory Assist. Addresses [RFC2132] */
+ dhcp_code_User_Class= 77 ,/**< User-Class N User Class Information [RFC3004] */
+ dhcp_code_Directory_Agent = 78 ,/**< Directory Agent N directory agent information [RFC2610] */
+ dhcp_code_Service_Scope = 79 ,/**< Service Scope N service location agent scope [RFC2610] */
+ dhcp_code_Rapid_Commit= 80 ,/**< Rapid Commit 0 Rapid Commit [RFC4039] */
+ dhcp_code_Client_FQDN = 81 ,/**< Client FQDN N Fully Qualified Domain Name [RFC4702] */
+ dhcp_code_Relay_Agent_Information= 82 ,/**< Relay Agent Information N Relay Agent Information [RFC3046] */
+ dhcp_code_iSNS= 83 ,/**< iSNS N Internet Storage Name Service [RFC4174] */
+ //84 REMOVED/Unassigned [RFC3679] */
+ dhcp_code_NDS_Servers= 85 ,/**< NDS Servers N Novell Directory Services [RFC2241] */
+ dhcp_code_NDS_Tree_Name= 86 ,/**< NDS Tree Name N Novell Directory Services [RFC2241] */
+ dhcp_code_NDS_Context= 87 ,/**< NDS Context N Novell Directory Services [RFC2241] */
+ dhcp_code_BCMCS_Controller_Domain_Name_list= 88 ,/**< BCMCS Controller Domain Name list [RFC4280] */
+ dhcp_code_BCMCS_Controller_IPv4_address_option= 89 ,/**< BCMCS Controller IPv4 address option [RFC4280] */
+ dhcp_code_Authentication= 90 ,/**< Authentication N Authentication [RFC3118] */
+ dhcp_code_client_last_transaction_time= 91 ,/**< client-last-transaction-time option [RFC4388] */
+ dhcp_code_associated_ip= 92 ,/**< associated-ip option [RFC4388] */
+ dhcp_code_Client_System = 93 ,/**< Client System N Client System Architecture [RFC4578] */
+ dhcp_code_Client_NDI = 94 ,/**< Client NDI N Client Network Device Interface [RFC4578] */
+ dhcp_code_LDAP= 95 ,/**< LDAP N Lightweight Directory Access Protocol [RFC3679] */
+ dhcp_code_REMOVED_Unassigned= 96 ,/**< REMOVED/Unassigned [RFC3679] */
+ dhcp_code_UUID_GUID= 97 ,/**< UUID/GUID N UUID/GUID-based Client Identifier [RFC4578] */
+ dhcp_code_User_Auth= 98 ,/**< User-Auth N Open Group's User Authentication [RFC2485] */
+ dhcp_code_GEOCONF_CIVIC= 99 ,/**< GEOCONF_CIVIC [RFC4776] */
+ dhcp_code_PCode= 100 ,/**< PCode N IEEE 1003.1 TZ String [RFC4833] */
+ dhcp_code_TCode= 101 ,/**< TCode N Reference to the TZ Database [RFC4833] */
+ //102-107 REMOVED/Unassigned [RFC3679]
+ //108 REMOVED/Unassigned [RFC3679]
+ //109 Unassigned [RFC3679]
+ //110 REMOVED/Unassigned [RFC3679]
+ //111 Unassigned [RFC3679]
+ dhcp_code_Netinfo_Address= 112 ,/**< Netinfo Address N NetInfo Parent Server Address [RFC3679] */
+ dhcp_code_Netinfo_Tag= 113 ,/**< Netinfo Tag N NetInfo Parent Server Tag [RFC3679] */
+ dhcp_code_= 114 ,/**< URL N URL [RFC3679] */
+ //115 REMOVED/Unassigned [RFC3679]
+ dhcp_code_Auto_Config= 116 ,/**< Auto-Config N DHCP Auto-Configuration [RFC2563] */
+ dhcp_code_Name_Service_Search= 117 ,/**< Name Service Search N Name Service Search [RFC2937] */
+ dhcp_code_Subnet_Selection_Option= 118 ,/**< Subnet Selection Option 4 Subnet Selection Option [RFC3011] */
+ dhcp_code_Domain_Search= 119 ,/**< Domain Search N DNS domain search list [RFC3397] */
+ dhcp_code_SIP_Servers_DHCP_Option= 120 ,/**< SIP Servers DHCP Option N SIP Servers DHCP Option [RFC3361] */
+ dhcp_code_Classless_Static_Route_Option= 121 ,/**< Classless Static Route Option N Classless Static Route Option [RFC3442] */
+ dhcp_code_CCC= 122 ,/**< CCC N CableLabs Client Configuration [RFC3495] */
+ dhcp_code_GeoConf_Option= 123 ,/**< GeoConf Option 16 GeoConf Option [RFC3825] */
+ dhcp_code_V_I_Vendor_Class= 124 ,/**< V-I Vendor Class Vendor-Identifying Vendor Class [RFC3925] */
+ dhcp_code_V_I_Vendor_Specific_Information= 125 ,/**< V-I Vendor-Specific Information Vendor-Identifying Vendor-Specific Information [RFC3925] */
+ //dhcp_code_= 126 ,/**< Removed/Unassigned [RFC3679] */
+ //dhcp_code_= 127 ,/**< Removed/Unassigned [RFC3679] */
+ //dhcp_code_PXE - undefined= 128 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Etherboot_signature= 128 ,/**< Etherboot signature. 6 bytes: E4:45:74:68:00:00 */
+ dhcp_code_DOCSIS= 128 ,/**< DOCSIS "full security" server IP address */
+ dhcp_code_TFTP_Server_IP= 128 ,/**< TFTP Server IP address (for IP Phone software load) */
+ //dhcp_code_= 129 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Kernel_options= 129 ,/**< Kernel options. Variable length string */
+ dhcp_code_Call_Server_IP= 129 ,/**< Call Server IP address */
+ //dhcp_code_= 130 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Ethernet_interface= 130 ,/**< Ethernet interface. Variable length string. */
+ dhcp_code_Discrimination= 130 ,/**< Discrimination string (to identify vendor) */
+ //dhcp_code_= 131 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_Remote_statistics_server_IP= 131 ,/**< Remote statistics server IP address */
+ //dhcp_code_= 132 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_IEEE_802_1Q_VLAN_ID= 132 ,/**< IEEE 802.1Q VLAN ID */
+ //dhcp_code_= 133 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_IEEE_802_1D_p= 133 ,/**< IEEE 802.1D/p Layer 2 Priority */
+ //dhcp_code_= 134 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_DSCP= 134 ,/**< Diffserv Code Point (DSCP) for VoIP signalling and media streams */
+ //dhcp_code_= 135 ,/**< PXE - undefined (vendor specific) [RFC4578] */
+ dhcp_code_HTTP_Proxy= 135 ,/**< HTTP Proxy for phone-specific applications */
+ dhcp_code_OPTION_PANA_AGENT= 136 ,/**< OPTION_PANA_AGENT [RFC5192] */
+ dhcp_code_OPTION_V4_LOST= 137 ,/**< OPTION_V4_LOST [RFC5223] */
+ dhcp_code_OPTION_CAPWAP_AC_V4= 138 ,/**< OPTION_CAPWAP_AC_V4 N CAPWAP Access Controller addresses [RFC5417] */
+ dhcp_code_OPTION_IPv4_Address_MoS= 139 ,/**< OPTION-IPv4_Address-MoS N a series of suboptions [RFC5678] */
+ dhcp_code_OPTION_IPv4_FQDN_MoS= 140 ,/**< OPTION-IPv4_FQDN-MoS N a series of suboptions [RFC5678] */
+ //141-149 Unassigned [RFC3942] */
+ dhcp_code_TFTP_server_address= 150 ,/**< TFTP server address (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_Etherboot= 150 ,/**< Etherboot */
+ dhcp_code_GRUB_configuration_path_name= 150 ,/**< GRUB configuration path name */
+ //151-174 Unassigned [RFC3942]
+ //dhcp_code_Etherboot= 175 ,/**< Etherboot (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_IP_Telephone= 176 ,/**< IP Telephone (Tentatively Assigned - 2005-06-23) */
+ //dhcp_code_Etherboot= 177 ,/**< Etherboot (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_PacketCable_and_CableHome= 177 ,/**< PacketCable and CableHome (replaced by 122) */
+ //178-207 Unassigned [RFC3942]
+ dhcp_code_PXELINUX_Magic= 208 ,/**< PXELINUX Magic 4 magic string = F1:00:74:7E [RFC5071] Deprecated */
+ dhcp_code_Configuration_File= 209 ,/**< Configuration File N Configuration file [RFC5071] */
+ dhcp_code_Path_Prefix= 210 ,/**< Path Prefix N Path Prefix Option [RFC5071] */
+ dhcp_code_Reboot_Time = 211 ,/**< Reboot Time 4 Reboot Time [RFC5071] */
+ // 212-219 Unassigned
+ dhcp_code_Subnet_Allocation= 220 ,/**< Subnet Allocation Option (Tentatively Assigned - 2005-06-23) */
+ dhcp_code_Virtual_Subnet= 221 ,/**< Virtual Subnet Selection Option (Tentatively Assigned - 2005-06-23) */
+ // 222-223 Unassigned [RFC3942]
+ //224-254 Reserved (Private Use)
+ dhcp_code_null=224 ,
+ dhcp_code_End= 255 ,/**< End 0 None [RFC2132] */
+}
+tnet_dhcp_option_code_t;
+
+/** DHCP/BOOTP option as per RFC 2132.
+* Format ==> subclause 2.
+*/
+typedef struct tnet_dhcp_option_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t initialized;
+
+ tnet_dhcp_option_code_t code; /**< 1-byte option-code. */
+ tsk_buffer_t *value;
+}
+tnet_dhcp_option_t;
+
+typedef tsk_list_t tnet_dhcp_options_L_t;
+
+#define TNET_DECLARE_DHCP_OPTION tnet_dhcp_option_t dhcp_option
+
+int tnet_dhcp_option_init(tnet_dhcp_option_t *self, tnet_dhcp_option_code_t code);
+int tnet_dhcp_option_deinit(tnet_dhcp_option_t *self);
+
+tnet_dhcp_option_t* tnet_dhcp_option_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp_option_serialize(const tnet_dhcp_option_t* self, tsk_buffer_t *output);
+int tnet_dhcp_option_serializeex(tnet_dhcp_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output);
+
+/*=======================================================================================
+* RFC 2132 - 9.8. Parameter Request List
+*=======================================================================================*/
+
+/** Parameter Request List Option */
+typedef struct tnet_dhcp_option_paramslist_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 2132 - 9.8. Parameter Request List
+ Code Len Option Codes
+ +-----+-----+-----+-----+---
+ | 55 | n | c1 | c2 | ...
+ +-----+-----+-----+-----+---
+ */
+}
+tnet_dhcp_option_paramslist_t;
+int tnet_dhcp_option_paramslist_add_code(tnet_dhcp_option_paramslist_t* self, tnet_dhcp_option_code_t code);
+
+/*=======================================================================================
+* RFC 2132 - 3.8. Domain Name Server Option
+*=======================================================================================*/
+
+/** Domain Name Server Option */
+typedef struct tnet_dhcp_option_dns_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 2132 - 3.8. Domain Name Server Option
+ Code Len Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ tsk_strings_L_t *servers;
+}
+tnet_dhcp_option_dns_t;
+
+TINYNET_API tnet_dhcp_option_t* tnet_dhcp_option_create(tnet_dhcp_option_code_t code);
+TINYNET_API tnet_dhcp_option_paramslist_t* tnet_dhcp_option_paramslist_create();
+TINYNET_API tnet_dhcp_option_dns_t* tnet_dhcp_option_dns_create(const void* payload, tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ns_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_paramslist_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_dns_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP_OPTION_H */
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option_sip.c b/tinyNET/src/dhcp/tnet_dhcp_option_sip.c
new file mode 100644
index 0000000..69d564e
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option_sip.c
@@ -0,0 +1,131 @@
+/*
+* 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_dhcp_option_sip.c
+ * @brief Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for
+ * Session Initiation Protocol (SIP) Servers as per RFC 3361.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp_option_sip.h"
+
+#include "dns/tnet_dns_rr.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+
+tnet_dhcp_option_sip_t* tnet_dhcp_option_sip_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp_option_sip_def_t, payload, payload_size);
+}
+
+//
+// [[DHCP SIP4]] object definition
+//
+static tsk_object_t* tnet_dhcp_option_sip_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp_option_sip_t *option = self;
+ if(option){
+ 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;
+ const uint8_t* payloadEnd = (payloadPtr + payload_size);
+
+ /* init base */
+ tnet_dhcp_option_init(TNET_DHCP_OPTION(option), dhcp_code_SIP_Servers_DHCP_Option);
+
+ option->servers = tsk_list_create();
+
+ /* Set values as per RFC 3361. */
+ if(*payloadPtr == 0){ /* enc=0 */
+ /*
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ |120|27 | 0 | 7 |'e'|'x'|'a'|'m'|'p'|'l'|'e'| 3 |'c'|'o'|'m'| 0 |
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ +---+---+---+---+---+---+---+---+---+---+---+---+---+ | 7
+ |'e'|'x'|'a'|'m'|'p'|'l'|'e'| 3 |'n'|'e'|'t'| 0 | +---+---+---
+ +---+---+---+---+---+---+---+---+---+---+
+ */
+ tsk_size_t offset = 1;
+ char* server = 0;
+ payloadPtr++;
+ while((payloadPtr < payloadEnd) && !tnet_dns_rr_qname_deserialize(payload, &server, &offset)){
+ tsk_string_t* string = tsk_string_create(server);
+ tsk_list_push_back_data(option->servers, (void*)&string);
+ TSK_FREE(server);
+ payloadPtr += offset;
+ }
+ }
+ else{
+ /*
+ Code Len enc Address 1 Address 2
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 120 | n | 1 | a1 | a2 | a3 | a4 | a1 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ uint32_t address;
+ tsk_string_t* addrstring;
+ char* ip4 = 0;
+
+ while(payloadPtr < payloadEnd){
+ ++payloadPtr;
+ address = tnet_htonl_2(payloadPtr);
+
+ tsk_sprintf(&ip4, "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+
+ addrstring = tsk_string_create(ip4);
+ tsk_list_push_back_data(option->servers, (void*)&addrstring);
+
+ TSK_FREE(ip4);
+
+ payloadPtr+= 4;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp_option_sip_dtor(tsk_object_t * self)
+{
+ tnet_dhcp_option_sip_t *option = self;
+ if(option){
+ /* deinit base */
+ tnet_dhcp_option_deinit(TNET_DHCP_OPTION(option));
+
+ TSK_OBJECT_SAFE_FREE(option->servers);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp_option_sip_def_s =
+{
+ sizeof(tnet_dhcp_option_sip_t),
+ tnet_dhcp_option_sip_ctor,
+ tnet_dhcp_option_sip_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp_option_sip_def_t = &tnet_dhcp_option_sip_def_s;
diff --git a/tinyNET/src/dhcp/tnet_dhcp_option_sip.h b/tinyNET/src/dhcp/tnet_dhcp_option_sip.h
new file mode 100644
index 0000000..8db7049
--- /dev/null
+++ b/tinyNET/src/dhcp/tnet_dhcp_option_sip.h
@@ -0,0 +1,62 @@
+/*
+* 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_dhcp_option_sip.h
+ * @brief Dynamic Host Configuration Protocol (DHCP-for-IPv4) Option for
+ * Session Initiation Protocol (SIP) Servers as per RFC 3361.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef tnet_dhcp_option_sip_H
+#define tnet_dhcp_option_sip_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp_option.h"
+
+#include "tsk_string.h"
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_dhcp_option_sip_s
+{
+ TNET_DECLARE_DHCP_OPTION;
+
+ /* RFC 3361 subclause 3.1
+ Code Len enc DNS name of SIP server
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ | 120 | n | 0 | s1 | s2 | s3 | s4 | s5 | ...
+ +-----+-----+-----+-----+-----+-----+-----+-----+--
+ */
+ tsk_strings_L_t *servers;
+}
+tnet_dhcp_option_sip_t;
+
+TINYNET_API tnet_dhcp_option_sip_t* tnet_dhcp_option_sip_create(const void* payload, tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp_option_sip_def_t;
+
+TNET_END_DECLS
+
+#endif /* #define tnet_dhcp_option_sip_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6.c b/tinyNET/src/dhcp6/tnet_dhcp6.c
new file mode 100644
index 0000000..cc52476
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6.c
@@ -0,0 +1,269 @@
+/*
+* 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_dhcp6.c
+ * @brief Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+ * Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp6.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_thread.h"
+
+
+/**@defgroup tnet_dhcp6_group DHCPv6 (RFC 3315) implementation.
+* Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+* Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+*/
+
+tnet_dhcp6_ctx_t* tnet_dhcp6_ctx_create()
+{
+ return tsk_object_new(tnet_dhcp6_ctx_def_t);
+}
+
+/**@ingroup tnet_dhcp6_group
+*/
+tnet_dhcp6_reply_t* tnet_dhcp6_send_request(const tnet_dhcp6_ctx_t* ctx, tnet_dhcp6_request_t* request)
+{
+ tsk_buffer_t *output;
+ tnet_dhcp6_reply_t* reply = 0;
+ int ret;
+ struct timeval tv;
+ fd_set set;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_interface_t *iface;
+ tnet_ip_t bestsource;
+
+ tnet_socket_t *localsocket6 = 0;
+ struct sockaddr_storage server;
+
+ if(!ctx || !request){
+ goto bail;
+ }
+
+ if((ret = tnet_getbestsource(TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port, tnet_socket_type_udp_ipv6, &bestsource))){
+ TSK_DEBUG_WARN("Failed to get best source for [%s]:%u.", TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port);
+ //fe80::21b:63ff:fea9:c14e%4
+ localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, ctx->port_client, tnet_socket_type_udp_ipv6);
+ }
+ else{
+ localsocket6 = tnet_socket_create(bestsource, ctx->port_client, tnet_socket_type_udp_ipv6);
+ }
+
+ /* Check local socket. */
+ if(!TNET_SOCKET_IS_VALID(localsocket6)){
+ TSK_DEBUG_ERROR("Failed to create/bind DHCPv6 client socket.");
+ goto bail;
+ }
+
+ /* Always wait for 200ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (200 * 1000);
+
+ if(tnet_sockaddr_init(TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers, ctx->server_port, tnet_socket_type_udp_ipv6, &server)){
+ TNET_PRINT_LAST_ERROR("Failed to initialize the DHCPv6 server address.");
+ goto bail;
+ }
+
+ /* Set timeout */
+ timeout = tsk_time_epoch() + ctx->timeout;
+
+ do
+ {
+ tsk_list_foreach(item, ctx->interfaces){
+ iface = item->data;
+
+ /* Set FD */
+ FD_ZERO(&set);
+ FD_SET(localsocket6->fd, &set);
+
+ ///* ciaddr */
+ //if(request->type == dhcp_type_inform){
+ // struct sockaddr_storage ss;
+ // if(!tnet_get_sockaddr(localsocket4->fd, &ss)){
+ // uint32_t addr = tnet_htonl_2(&((struct sockaddr_in*)&ss)->sin_addr);
+ // memcpy(&request->ciaddr, &addr, 4);
+ // }
+ //}
+
+ ///* chaddr */
+ //memset(request->chaddr, 0, sizeof(request->chaddr));
+ //request->hlen = iface->mac_address_length > sizeof(request->chaddr) ? sizeof(request->chaddr) : iface->mac_address_length;
+ //memcpy(request->chaddr, iface->mac_address, request->hlen);
+
+ /* Serialize and send to the server. */
+ if(!(output = tnet_dhcp6_message_serialize(ctx, request))){
+ TSK_DEBUG_ERROR("Failed to serialize the DHCPv6 message.");
+ goto next_iface;
+ }
+ /* Send the request to the DHCP server */
+ if((ret =tnet_sockfd_sendto(localsocket6->fd, (const struct sockaddr*)&server, output->data, output->size))<0){
+ TNET_PRINT_LAST_ERROR("Failed to send DHCPv6 request.");
+
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ /* wait for response */
+ if((ret = select(localsocket6->fd+1, &set, NULL, NULL, &tv))<0){ /* Error */
+ TNET_PRINT_LAST_ERROR("select have failed.");
+ tsk_thread_sleep(150); // wait 150ms before trying the next iface.
+ goto next_iface;
+ }
+ else if(ret == 0){ /* timeout ==> do nothing */
+ }
+ else{ /* there is data to read. */
+ tsk_size_t len = 0;
+ void* data = 0;
+
+ /* Check how how many bytes are pending */
+ if((ret = tnet_ioctlt(localsocket6->fd, FIONREAD, &len))<0){
+ goto next_iface;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if((ret = tnet_sockfd_recv(localsocket6->fd, data, len, 0))<0){
+ TSK_FREE(data);
+
+ TNET_PRINT_LAST_ERROR("Failed to receive DHCP dgrams.");
+ goto next_iface;
+ }
+
+ /* Parse the incoming response. */
+ reply = tnet_dhcp6_message_deserialize(ctx, data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if(reply)
+ { /* response successfuly parsed */
+ if(request->transaction_id != reply->transaction_id)
+ { /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(reply);
+ }
+ }
+ }
+
+ next_iface:
+ TSK_OBJECT_SAFE_FREE(output);
+ if(reply){
+ goto bail;
+ }
+ }
+ break;//FIXME
+ }
+ while(timeout > tsk_time_epoch());
+
+bail:
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+
+ return reply;
+}
+
+
+
+
+
+
+/**@ingroup tnet_dhcp6_group
+*/
+tnet_dhcp6_reply_t* tnet_dhcp6_requestinfo(const tnet_dhcp6_ctx_t* ctx, const tnet_dhcp6_option_orequest_t *orequest)
+{
+ tnet_dhcp6_reply_t* reply = 0;
+ tnet_dhcp6_request_t* request = tnet_dhcp6_request_create(dhcp6_type_information_request);
+ tnet_dhcp6_option_t* option = 0;
+
+ if(!ctx || !orequest || !request){
+ goto bail;
+ }
+
+ if((option = tnet_dhcp6_option_create(dhcp6_code_oro, orequest, sizeof(*orequest)))){
+ tsk_list_push_back_data(request->options, (void**)&option);
+ }
+
+ /* Vendor class */
+ {
+
+ }
+
+ reply = tnet_dhcp6_send_request(ctx, request);
+
+bail:
+
+ return reply;
+}
+
+
+
+
+
+//=================================================================================================
+// [[DHCPv6 CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dhcp6_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_ctx_t *ctx = self;
+ if(ctx){
+ ctx->pen = TNET_IANA_PEN;
+ ctx->vendor_class_data = tsk_strdup(TNET_DHCP6_VENDOR_CLASS_DATA_DEFAULT);
+
+ ctx->port_client = TNET_DHCP6_CLIENT_PORT;
+ ctx->server_port = TNET_DHCP6_SERVER_PORT;
+ ctx->interfaces = tnet_get_interfaces();
+
+ ctx->timeout = 0xffff; /* FIXME */
+
+ if(!ctx->interfaces || TSK_LIST_IS_EMPTY(ctx->interfaces)){
+ TSK_DEBUG_ERROR("Failed to retrieve network interfaces.");
+ }
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_ctx_t *ctx = self;
+ if(ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_FREE(ctx->vendor_class_data);
+
+ TSK_OBJECT_SAFE_FREE(ctx->interfaces);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_ctx_def_s =
+{
+ sizeof(tnet_dhcp6_ctx_t),
+ tnet_dhcp6_ctx_ctor,
+ tnet_dhcp6_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_ctx_def_t = &tnet_dhcp6_ctx_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6.h b/tinyNET/src/dhcp6/tnet_dhcp6.h
new file mode 100644
index 0000000..893aaa4
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6.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_dhcp6.h
+ * @brief Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as per RFC 3315.
+ * Also implement: RFC 3319, 3633, 3646, 3736, 4242, 5007 ...
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DHCP6_H
+#define TNET_DHCP6_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_object.h"
+#include "tsk_safeobj.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_VENDOR_CLASS_DATA_DEFAULT "doubango/v0.0.0"
+
+/** RFC 3315 - 5.1. Multicast Addresses
+* A link-scoped multicast address used by a client to communicate with
+* neighboring (i.e., on-link) relay agents and servers.
+* All servers and relay agents are members of this multicast group.
+*/
+#define TNET_DHCP6_All_DHCP_Relay_Agents_and_Servers "FF02::1:2"
+
+/** RFC 3315 - 5.1. Multicast Addresses
+* A site-scoped multicast address used by a relay agent to communicate with servers, either
+* because the relay agent wants to send messages to all servers or because it does not know the unicast
+* addresses of the servers. Note that in order for a relay agent to use this address, it must have an
+* address of sufficient scope to be reachable by the servers. All servers within the site are members of
+* this multicast group.
+*/
+#define TNET_DHCP6_All_DHCP_Servers "FF05::1:3"
+
+/*== RFC 3315 - 5.5. Transmission and Retransmission Parameters
+ * This section presents a table of values used to describe the message
+ * transmission behavior of clients and servers.
+*/
+#define TNET_DHCP6_RT_SOL_MAX_DELAY 1 /**< 1 sec Max delay of first Solicit */
+#define TNET_DHCP6_RT_SOL_TIMEOUT 1 /**< 1 sec Initial Solicit timeout */
+#define TNET_DHCP6_RT_SOL_MAX_RT 120 /**< 120 secs Max Solicit timeout value */
+#define TNET_DHCP6_RT_REQ_TIMEOUT 1 /**< 1 sec Initial Request timeout */
+#define TNET_DHCP6_RT_REQ_MAX_RT 30 /**< 30 secs Max Request timeout value */
+#define TNET_DHCP6_RT_REQ_MAX_RC 10 /**< 10 Max Request retry attempts */
+#define TNET_DHCP6_RT_CNF_MAX_DELAY 1 /**< 1 sec Max delay of first Confirm */
+#define TNET_DHCP6_RT_CNF_TIMEOUT 1 /**< 1 sec Initial Confirm timeout */
+#define TNET_DHCP6_RT_CNF_MAX_RT 4 /**< 4 secs Max Confirm timeout */
+#define TNET_DHCP6_RT_CNF_MAX_RD 10 /**< 10 secs Max Confirm duration */
+#define TNET_DHCP6_RT_REN_TIMEOUT 10 /**< 10 secs Initial Renew timeout */
+#define TNET_DHCP6_RT_REN_MAX_RT 600 /**< 600 secs Max Renew timeout value */
+#define TNET_DHCP6_RT_REB_TIMEOUT 10 /**< 10 secs Initial Rebind timeout */
+#define TNET_DHCP6_RT_REB_MAX_RT 600 /**< 600 secs Max Rebind timeout value */
+#define TNET_DHCP6_RT_INF_MAX_DELAY 1 /**< 1 sec Max delay of first Information-request */
+#define TNET_DHCP6_RT_INF_TIMEOUT 1 /**< 1 sec Initial Information-request timeout */
+#define TNET_DHCP6_RT_INF_MAX_RT 120 /**< 120 secs Max Information-request timeout value */
+#define TNET_DHCP6_RT_REL_TIMEOUT 1 /**< 1 sec Initial Release timeout */
+#define TNET_DHCP6_RT_REL_MAX_RC 5 /**< 5 MAX Release attempts */
+#define TNET_DHCP6_RT_DEC_TIMEOUT 1 /**< 1 sec Initial Decline timeout */
+#define TNET_DHCP6_RT_DEC_MAX_RC 5 /**< 5 Max Decline attempts */
+#define TNET_DHCP6_RT_REC_TIMEOUT 2 /**< 2 secs Initial Reconfigure timeout */
+#define TNET_DHCP6_RT_REC_MAX_RC 2 /**< 8 Max Reconfigure attempts */
+#define TNET_DHCP6_RT_HOP_COUNT_LIMIT 32 /**< 32 Max hop count in a Relay-forward message */
+
+/** RFC 3315 - 5.6 Representation of time values and "Infinity" as a time value */
+#define TNET_DHCP6_TIMEVAL_INFINITY 0XFFFFFFFF
+
+/**< Local port(client) to bind to for incoming DHCP messages as per RFC 3315 subclause 5.2. */
+#define TNET_DHCP6_CLIENT_PORT 546
+/**< Destination port(Server) for outgoing DHCP messages as per RFC 3315 subclause 5.2. */
+#define TNET_DHCP6_SERVER_PORT 547
+
+/**@ingroup tnet_dhcpv_group
+* DHCPv6 context.
+*/
+typedef struct tnet_dhcp6_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint16_t pen; /**< Private Enterprise Number assigned by the IANA. Default= @ref TNET_IANA_PEN.*/
+ char* vendor_class_data;
+
+ uint64_t timeout;
+
+ tnet_port_t port_client; /**< Local port to bind to for incloming DHCPv6 messages. Default: 546 */
+ tnet_port_t server_port; /**< Destination port for outgoing DHCPv6 messages. Default: 547 */
+ tnet_interfaces_L_t *interfaces;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dhcp6_ctx_t;
+
+TINYNET_API tnet_dhcp6_reply_t* tnet_dhcp6_requestinfo(const tnet_dhcp6_ctx_t* ctx, const tnet_dhcp6_option_orequest_t *orequest);
+
+TINYNET_API tnet_dhcp6_ctx_t* tnet_dhcp6_ctx_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_ctx_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_duid.c b/tinyNET/src/dhcp6/tnet_dhcp6_duid.c
new file mode 100644
index 0000000..378ba3c
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_duid.c
@@ -0,0 +1,288 @@
+/*
+* 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_dhcp6_duid.c
+ * @brief DHCPv6 (RFC 3315) DHCP Unique Identifier (DUID) as defined in subclause 9.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp6_duid.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+int tnet_dhcp6_duid_llt_serialize(const tnet_dhcp6_duid_llt_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_duid_en_serialize(const tnet_dhcp6_duid_en_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_duid_ll_serialize(const tnet_dhcp6_duid_ll_t* self, tsk_buffer_t *output);
+
+
+tnet_dhcp6_duid_llt_t* tnet_dhcp6_duid_llt_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_llt_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_duid_en_t* tnet_dhcp6_duid_en_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_en_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_duid_ll_t* tnet_dhcp6_duid_ll_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_duid_ll_def_t, payload, payload_size);
+}
+
+int tnet_dhcp6_duid_init(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type)
+{
+ if(self){
+ if(!self->initialized){
+ self->type = type;
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+int tnet_dhcp6_duid_deinit(tnet_dhcp6_duid_t *self)
+{
+ if(self){
+ if(self->initialized){
+ self->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+tnet_dhcp6_duid_t* tnet_dhcp6_duid_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp6_duid_t *duid = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp6_duid_type_t type;
+ //uint8_t len = 0;
+
+ /* Check validity */
+ if(!dataPtr || size<2/*Type*/){
+ goto bail;
+ }
+
+ type = (tnet_dhcp6_duid_type_t) tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+bail:
+ return duid;
+}
+
+int tnet_dhcp6_duid_serialize(const tnet_dhcp6_duid_t* self, tsk_buffer_t *output)
+{
+ int ret = -1;
+
+ if(!self || !output){
+ return ret;
+ }
+
+ switch(self->type){
+ case dhcp6_duid_linklayer_plus_time:
+ {
+ ret = tnet_dhcp6_duid_llt_serialize(TNET_DHCP6_DUID_LLT(self), output);
+ break;
+ }
+
+ case dhcp6_duid_Vendor_assigned_id:
+ {
+ ret = tnet_dhcp6_duid_en_serialize(TNET_DHCP6_DUID_EN(self), output);
+ break;
+ }
+
+ case dhcp6_duid_linklayer:
+ {
+ ret = tnet_dhcp6_duid_ll_serialize(TNET_DHCP6_DUID_LL(self), output);
+ break;
+ }
+
+ default:
+ {
+ ret = -2;
+ goto bail;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+/*=======================================================================================
+* RFC 3315 - 9.2. DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_llt_serialize(const tnet_dhcp6_duid_llt_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-LLT]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_llt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_llt_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_linklayer_plus_time);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_llt_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_llt_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_llt_def_s =
+{
+ sizeof(tnet_dhcp6_duid_llt_t),
+ tnet_dhcp6_duid_llt_ctor,
+ tnet_dhcp6_duid_llt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_llt_def_t = &tnet_dhcp6_duid_llt_def_s;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.3. DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_en_serialize(const tnet_dhcp6_duid_en_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-EN]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_en_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_en_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_Vendor_assigned_id);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_en_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_en_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->indentifier);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_en_def_s =
+{
+ sizeof(tnet_dhcp6_duid_en_t),
+ tnet_dhcp6_duid_en_ctor,
+ tnet_dhcp6_duid_en_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_en_def_t = &tnet_dhcp6_duid_en_def_s;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.4. DUID Based on Link-layer Address [DUID-LL]
+*=======================================================================================*/
+
+int tnet_dhcp6_duid_ll_serialize(const tnet_dhcp6_duid_ll_t* self, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 DUID-LL]] object definition
+//
+static tsk_object_t* tnet_dhcp6_duid_ll_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_duid_ll_t *duid = self;
+ if(duid){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dhcp6_duid_init(TNET_DHCP6_DUID(duid), dhcp6_duid_linklayer);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_duid_ll_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_duid_ll_t *duid = self;
+ if(duid){
+ /* deinit base */
+ tnet_dhcp6_duid_deinit(TNET_DHCP6_DUID(duid));
+
+ TSK_OBJECT_SAFE_FREE(duid->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_duid_ll_def_s =
+{
+ sizeof(tnet_dhcp6_duid_ll_t),
+ tnet_dhcp6_duid_ll_ctor,
+ tnet_dhcp6_duid_ll_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_duid_ll_def_t = &tnet_dhcp6_duid_ll_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_duid.h b/tinyNET/src/dhcp6/tnet_dhcp6_duid.h
new file mode 100644
index 0000000..9331ab3
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_duid.h
@@ -0,0 +1,185 @@
+/*
+* 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_dhcp6_duid.h
+ * @brief DHCPv6 (RFC 3315) DHCP Unique Identifier (DUID) as defined in subclause 9.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DHCP6_duid_H
+#define TNET_DHCP6_duid_H
+
+#include "tinynet_config.h"
+
+#include "tnet_hardwares.h"
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_DUID(self) ((tnet_dhcp6_duid_t*)(self))
+#define TNET_DHCP6_DUID_LLT(self) ((tnet_dhcp6_duid_llt_t*)(self))
+#define TNET_DHCP6_DUID_EN(self) ((tnet_dhcp6_duid_en_t*)(self))
+#define TNET_DHCP6_DUID_LL(self) ((tnet_dhcp6_duid_ll_t*)(self))
+
+/** List of DHCPv6 DUIDs types as per RFC 3315 subclause 9.1.
+*/
+typedef enum tnet_dhcp6_duid_type_e
+{
+ dhcp6_duid_linklayer_plus_time = 1, /**< Link-layer address plus time. */
+ dhcp6_duid_Vendor_assigned_id = 2, /**< Vendor-assigned unique ID based on Enterprise Number. */
+ dhcp6_duid_linklayer = 3, /**< Link-layer address. */
+}
+tnet_dhcp6_duid_type_t;
+
+/** DHCP Unique Identifier (DUID) base class (subclause 9).
+*/
+typedef struct tnet_dhcp6_duid_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_bool_t initialized;
+
+ tnet_dhcp6_duid_type_t type; /* DUID type. 2-bytes value. */
+}
+tnet_dhcp6_duid_t;
+
+typedef tsk_list_t tnet_dhcp6_duids_L_t;
+
+#define TNET_DECLARE_DHCP6_DUID tnet_dhcp6_duid_t tnet_dhcp6_duid
+
+int tnet_dhcp6_duid_init(tnet_dhcp6_duid_t *self, tnet_dhcp6_duid_type_t type);
+int tnet_dhcp6_duid_deinit(tnet_dhcp6_duid_t *self);
+
+tnet_dhcp6_duid_t* tnet_dhcp6_duid_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp6_duid_serialize(const tnet_dhcp6_duid_t* self, tsk_buffer_t *output);
+
+/*=======================================================================================
+* RFC 3315 - 9.2. DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*=======================================================================================*/
+
+/** DUID Based on Link-layer Address Plus Time [DUID-LLT]
+*/
+typedef struct tnet_dhcp6_duid_llt_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 1 | hardware type (16 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | time (32 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . link-layer address (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* The hardware type code as maintained by IANA. */
+ tnet_hardware_type_t htype;
+ /* The time value is the time that the DUID is generated represented in seconds
+ since midnight (UTC), January 1, 2000, modulo 2^32. */
+ uint32_t time;
+ /* The link-layer address. */
+ tsk_buffer_t *address;
+}
+tnet_dhcp6_duid_llt_t;
+
+
+/*=======================================================================================
+* RFC 3315 - 9.3. DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*=======================================================================================*/
+
+/** DUID Assigned by Vendor Based on Enterprise Number [DUID-EN]
+*/
+typedef struct tnet_dhcp6_duid_en_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 2 | enterprise-number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | enterprise-number (contd) | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ . identifier .
+ . (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* Tthe vendor's registered Private Enterprise Number as maintained by IANA.
+ For more information: http://www.iana.org/assignments/enterprise-numbers. */
+ uint32_t en;
+ /* The link-layer address. */
+ tsk_buffer_t *indentifier;
+}
+tnet_dhcp6_duid_en_t;
+
+/*=======================================================================================
+* RFC 3315 - 9.4. DUID Based on Link-layer Address [DUID-LL]
+*=======================================================================================*/
+
+/** DUID Based on Link-layer Address [DUID-LL]
+*/
+typedef struct tnet_dhcp6_duid_ll_s
+{
+ TNET_DECLARE_DHCP6_DUID;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | 3 | hardware type (16 bits) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . link-layer address (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* The hardware type code as maintained by IANA. */
+ tnet_hardware_type_t htype;
+ /* The link-layer address. */
+ tsk_buffer_t *address;
+}
+tnet_dhcp6_duid_ll_t;
+
+
+
+
+
+
+TINYNET_API tnet_dhcp6_duid_llt_t* tnet_dhcp6_duid_llt_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_duid_en_t* tnet_dhcp6_duid_en_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_duid_ll_t* tnet_dhcp6_duid_ll_create(const void* payload, tsk_size_t payload_size);
+
+
+
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_llt_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_en_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_duid_ll_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_duid_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_message.c b/tinyNET/src/dhcp6/tnet_dhcp6_message.c
new file mode 100644
index 0000000..28304e1
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_message.c
@@ -0,0 +1,137 @@
+/*
+* 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_dhcp6_message.c
+ * @brief DHCPv6 (RFC 3315) Messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp6_message.h"
+#include "tnet_dhcp6.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+tnet_dhcp6_message_t* tnet_dhcp6_message_create(tnet_dhcp6_message_type_t type)
+{
+ return tsk_object_new(tnet_dhcp6_message_def_t, type);
+}
+
+tnet_dhcp6_request_t* tnet_dhcp6_request_create(tnet_dhcp6_message_type_t type)
+{
+ return tnet_dhcp6_message_create(type);
+}
+
+tsk_buffer_t* tnet_dhcp6_message_serialize(const tnet_dhcp6_ctx_t *ctx, const tnet_dhcp6_message_t *self)
+{
+ tsk_buffer_t* output = 0;
+ //uint8_t _1byte;
+ uint16_t _2bytes;
+ uint32_t _4bytes;
+
+ /* Check message validity */
+ if(!self){
+ goto bail;
+ }
+
+ output = tsk_buffer_create_null();
+
+ /*== msg-type + transaction-id */
+ _4bytes = (((uint32_t)(self->type)) << 24) | (self->transaction_id & 0xFFFFFF);
+ _4bytes = tnet_ntohl(_4bytes);
+ tsk_buffer_append(output, &(_4bytes), 4);
+
+ /*== Vendor class
+ */
+ {
+ _2bytes = tnet_htons(dhcp6_code_vendor_class);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ _2bytes = tnet_htons(4 + tsk_strlen(ctx->vendor_class_data));
+ tsk_buffer_append(output, &(_2bytes), 2);
+ _4bytes = tnet_ntohl(ctx->pen);
+ tsk_buffer_append(output, &(_4bytes), 4);
+ tsk_buffer_append(output, ctx->vendor_class_data, tsk_strlen(ctx->vendor_class_data));
+ }
+
+ /*== DHCP Options
+ */
+ {
+ tsk_list_item_t *item;
+ tnet_dhcp6_option_t* option;
+ tsk_list_foreach(item, self->options)
+ {
+ option = (tnet_dhcp6_option_t*)item->data;
+ if(tnet_dhcp6_option_serialize(option, output)){
+ TSK_DEBUG_WARN("Failed to serialize DHCPv6 OPTION (%u)", option->code);
+ }
+ }
+ }
+bail:
+ return output;
+}
+
+tnet_dhcp6_message_t* tnet_dhcp6_message_deserialize(const tnet_dhcp6_ctx_t *ctx, const uint8_t *data, tsk_size_t size)
+{
+ return 0;
+}
+
+
+
+//=================================================================================================
+// [[DHCPv6 MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dhcp6_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_message_t *message = self;
+ if(message){
+ static uint16_t __dhcp6message_unique_tid = 0;//(uint32_t)tsk_time_epoch();
+
+ message->type = va_arg(*app, tnet_dhcp6_message_type_t);
+ message->transaction_id = ++__dhcp6message_unique_tid;
+ message->options = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_message_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_message_t *message = self;
+ if(message){
+ TSK_OBJECT_SAFE_FREE(message->options);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_message_def_s =
+{
+ sizeof(tnet_dhcp6_message_t),
+ tnet_dhcp6_message_ctor,
+ tnet_dhcp6_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_message_def_t = &tnet_dhcp6_message_def_s;
+
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_message.h b/tinyNET/src/dhcp6/tnet_dhcp6_message.h
new file mode 100644
index 0000000..fdf545f
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_message.h
@@ -0,0 +1,143 @@
+/*
+* 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_dhcp6_message.h
+ * @brief DHCPv6 (RFC 3315) Messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DHCP6_MESSAGE_H
+#define TNET_DHCP6_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_option.h"
+
+#include "tsk_object.h"
+
+TNET_BEGIN_DECLS
+
+struct tnet_dhcp6_ctx_s;
+
+/** List of all supported DHCPv6 messages.
+* For more info: RFC 3315 - 5.3. DHCP Message Types
+*/
+typedef enum tnet_dhcp6_message_type_e
+{
+ /* A client sends a Solicit message to locate servers. */
+ dhcp6_type_solicit = 1,
+ /* A server sends an Advertise message to indicate that it is available for DHCP service, in
+ response to a Solicit message received from a client. */
+ dhcp6_type_advertise = 2,
+ /* A client sends a Request message to request configuration parameters, including IP
+ addresses, from a specific server. */
+ dhcp6_type_request = 3,
+ /* A client sends a Confirm message to any available server to determine whether the
+ addresses it was assigned are still appropriate to the link to which the client is connected. */
+ dhcp6_type_confirm = 4,
+ /* A client sends a Renew message to the server that originally provided the client's addresses
+ and configuration parameters to extend the lifetimes on the addresses assigned to the
+ client and to update other configurationparameters. */
+ dhcp6_type_renew = 5,
+ /* A client sends a Rebind message to any available server to extend the lifetimes on the
+ addresses assigned to the client and to update other configuration parameters; this message is
+ sent after a client receives no response to a Renew message.*/
+ dhcp6_type_rebind = 6,
+ /* A server sends a Reply message containing assigned addresses and configuration parameters
+ in response to a Solicit, Request, Renew, Rebind message received from a client. A
+ server sends a Reply message containing configuration parameters in response to an
+ Information-request message. A server sends a Reply message in response to a Confirm message
+ confirming or denying that the addresses assigned to the client are appropriate to the
+ link to which the client is connected. A server sends a Reply message to acknowledge
+ receipt of a Release or Decline message.*/
+ dhcp6_type_reply = 7,
+ /* A client sends a Release message to the server that assigned addresses to the client to
+ indicate that the client will no longer use one or more of the assigned addresses.*/
+ dhcp6_type_release = 8,
+ /* A client sends a Decline message to a server to indicate that the client has determined that
+ one or more addresses assigned by the server are already in use on the link to which the
+ client is connected.*/
+ dhcp6_type_decline = 9,
+ /*A server sends a Reconfigure message to a client to inform the client that the server has
+ new or updated configuration parameters, and that the client is to initiate a Renew/Reply
+ or Information-request/Reply transaction with the server in order to receive the updatedinformation. */
+ dhcp6_type_reconfigure = 10,
+ /* A client sends an Information-request message to a server to request configuration
+ parameters without the assignment of any IP addresses to the client.*/
+ dhcp6_type_information_request = 11,
+ /* A relay agent sends a Relay-forward message to relay messages to servers, either directly
+ or through another relay agent. The received message, either a client message or a
+ Relay-forward message from another relay agent, is encapsulated in an option in the Relay-forward message.*/
+ dhcp6_type_relay_forw = 12,
+ /* A server sends a Relay-reply message to a relay agent containing a message that the relay
+ agent delivers to a client. The Relay-reply message may be relayed by other relay agents
+ for delivery to the destination relay agent.
+ The server encapsulates the client message as an option in the Relay-reply message, which the
+ relay agent extracts and relays to the client.*/
+ dhcp6_type_relay_repl = 13,
+}
+tnet_dhcp6_message_type_t;
+
+
+/** DHCPv6 message (common fields) as per RFC 3315 subclause 6.
+*/
+typedef struct tnet_dhcp6_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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | msg-type | transaction-id |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ . options .
+ . (variable) .
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ /* Identifies the DHCP message type. 1-byte value. */
+ tnet_dhcp6_message_type_t type;
+ /* The transaction ID for this message exchange. 3-bytes value. */
+ uint32_t transaction_id;
+ /* Options carried in this message. */
+ tnet_dhcp6_options_L_t *options;
+}
+tnet_dhcp6_message_t;
+
+typedef tsk_list_t tnet_dhcp6_messages_L_t;
+typedef tnet_dhcp6_message_t tnet_dhcp6_request_t;
+typedef tnet_dhcp6_message_t tnet_dhcp6_reply_t;
+
+tsk_buffer_t* tnet_dhcp6_message_serialize(const struct tnet_dhcp6_ctx_s *ctx, const tnet_dhcp6_message_t *self);
+tnet_dhcp6_message_t* tnet_dhcp6_message_deserialize(const struct tnet_dhcp6_ctx_s *ctx, const uint8_t *data, tsk_size_t size);
+
+TINYNET_API tnet_dhcp6_message_t* tnet_dhcp6_message_create(tnet_dhcp6_message_type_t type);
+TINYNET_API tnet_dhcp6_request_t* tnet_dhcp6_request_create(tnet_dhcp6_message_type_t type);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_message_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_MESSAGE_H */
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_option.c b/tinyNET/src/dhcp6/tnet_dhcp6_option.c
new file mode 100644
index 0000000..7f7aca4
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_option.c
@@ -0,0 +1,336 @@
+/*
+* 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_dhcp6_option.c
+ * @brief DHCPv6 Options as per RFC 3315 subclause 22.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dhcp6_option.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+
+#include <string.h>
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_def_t, code, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_indentifer_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_identifier_def_t, code, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_clientid_create(const void* payload, tsk_size_t payload_size)
+{
+ return tnet_dhcp6_option_indentifer_create(dhcp6_code_clientid, payload, payload_size);
+}
+
+tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_serverid_create(const void* payload, tsk_size_t payload_size)
+{
+ return tnet_dhcp6_option_indentifer_create(dhcp6_code_serverid, payload, payload_size);
+}
+
+tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_orequest_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create_null()
+{
+ return tnet_dhcp6_option_orequest_create(tsk_null, 0);
+}
+
+tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dhcp6_option_vendorclass_def_t, payload, payload_size);
+}
+
+tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create_null()
+{
+ return tnet_dhcp6_option_vendorclass_create(tsk_null, 0);
+}
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_deserialize(const void* data, tsk_size_t size)
+{
+ tnet_dhcp6_option_t *option = 0;
+ uint8_t* dataPtr = ((uint8_t*)data);
+ //uint8_t* dataEnd = (dataPtr+size);
+
+ tnet_dhcp6_option_code_t code;
+ uint16_t len;
+
+ /* Check validity */
+ if(!dataPtr || size<4/*Code Len*/){
+ goto bail;
+ }
+
+ code = (tnet_dhcp6_option_code_t) tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ len = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ switch(code){
+ case dhcp6_code_clientid:
+ case dhcp6_code_serverid:
+ {
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+bail:
+ return option;
+}
+
+int tnet_dhcp6_option_serialize(const tnet_dhcp6_option_t* self, tsk_buffer_t *output)
+{
+ uint16_t _2bytes;
+ int ret = -1;
+
+ if(!self || !output){
+ goto bail;
+ }
+
+ /*== Code */
+ _2bytes = tnet_htons(self->code);
+ tsk_buffer_append(output, &(_2bytes), 2);
+
+ switch(self->code){
+ case dhcp6_code_clientid:
+ case dhcp6_code_serverid:
+ {
+ break;
+ }
+
+ case dhcp6_code_oro:
+ default:
+ {
+ if(self->data)
+ {
+ const tnet_dhcp6_option_orequest_t* opt = (const tnet_dhcp6_option_orequest_t*)self->data;
+ if(opt->codes){
+ /* option-len */
+ _2bytes = tnet_htons(opt->codes->size);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* option-data */
+ ret = tsk_buffer_append(output, opt->codes->data, opt->codes->size);
+ }
+
+ }
+ break;
+ }
+ }
+bail:
+ return ret;
+}
+
+int tnet_dhcp6_option_serializeex(tnet_dhcp6_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output)
+{
+ return -1;
+}
+
+//
+// [[DHCPv6 OPTION]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_t *option = self;
+ if(option){
+ tnet_dhcp6_option_code_t code = va_arg(*app, tnet_dhcp6_option_code_t);
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ option->code = code;
+ if(payload && payload_size){
+ if((option->data = (tnet_dhcp6_option_data_t*)tsk_calloc(payload_size, sizeof(uint8_t)))){
+ memcpy(option->data, payload, payload_size);
+ option->len = payload_size;
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_def_s =
+{
+ sizeof(tnet_dhcp6_option_t),
+ tnet_dhcp6_option_ctor,
+ tnet_dhcp6_option_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_def_t = &tnet_dhcp6_option_def_s;
+
+/*======================================================================================
+* RFC 3315 -
+ 22.2. Client Identifier Option
+ 22.3. Server Identifier Option
+*=======================================================================================*/
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_identifier_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_identifier_t *option = self;
+ if(option){
+ //tnet_dhcp6_option_code_t code = va_arg(*app, tnet_dhcp6_option_code_t);
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_identifier_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_identifier_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->duid);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_identifier_def_s =
+{
+ sizeof(tnet_dhcp6_option_identifier_t),
+ tnet_dhcp6_option_identifier_ctor,
+ tnet_dhcp6_option_identifier_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_identifier_def_t = &tnet_dhcp6_option_identifier_def_s;
+
+/*======================================================================================
+* RFC 3315 - 22.7. Option Request Option
+*=======================================================================================*/
+
+int tnet_dhcp6_option_orequest_add_code(tnet_dhcp6_option_orequest_t* self, uint16_t code)
+{
+ uint16_t _2bytes;
+ int ret = -1;
+ if(self){
+ if(!self->codes){
+ if(!(self->codes = tsk_buffer_create_null())){
+ return -3;
+ }
+ }
+ _2bytes = tnet_ntohs(code);
+ if(!(ret = tsk_buffer_append(self->codes, &_2bytes, 2))){
+ TNET_DHCP6_OPTION(self)->len += 2;
+ }
+ }
+ return ret;
+}
+
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_orequest_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_orequest_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size)
+ { /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_orequest_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_orequest_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->codes);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_orequest_def_s =
+{
+ sizeof(tnet_dhcp6_option_orequest_t),
+ tnet_dhcp6_option_orequest_ctor,
+ tnet_dhcp6_option_orequest_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_orequest_def_t = &tnet_dhcp6_option_orequest_def_s;
+
+/*======================================================================================
+* RFC 3315 - 22.16. Vendor Class Option
+*=======================================================================================*/
+
+//
+// [[DHCPv6 Option Request Option]] object definition
+//
+static tsk_object_t* tnet_dhcp6_option_vendorclass_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dhcp6_option_vendorclass_t *option = self;
+ if(option){
+ const void* payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ /* DESERIALIZATION */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dhcp6_option_vendorclass_dtor(tsk_object_t * self)
+{
+ tnet_dhcp6_option_vendorclass_t *option = self;
+ if(option){
+ TSK_OBJECT_SAFE_FREE(option->vendor_class_data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dhcp6_option_vendorclass_def_s =
+{
+ sizeof(tnet_dhcp6_option_vendorclass_t),
+ tnet_dhcp6_option_vendorclass_ctor,
+ tnet_dhcp6_option_vendorclass_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dhcp6_option_vendorclass_def_t = &tnet_dhcp6_option_vendorclass_def_s;
diff --git a/tinyNET/src/dhcp6/tnet_dhcp6_option.h b/tinyNET/src/dhcp6/tnet_dhcp6_option.h
new file mode 100644
index 0000000..efa843f
--- /dev/null
+++ b/tinyNET/src/dhcp6/tnet_dhcp6_option.h
@@ -0,0 +1,246 @@
+/*
+* 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_dhcp6_option.h
+ * @brief DHCPv6 Options as per RFC 3315 subclause 22.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DHCP6_OPTION_H
+#define TNET_DHCP6_OPTION_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dhcp6_duid.h"
+
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+#define TNET_DHCP6_OPTION(self) ((tnet_dhcp6_option_t*)(self))
+
+/** List of DHCPv6 option as registered by IANA (RFC 3315 subcaluse 24.3)*/
+typedef enum tnet_dhcp6_option_code_e
+{
+ dhcp6_code_clientid = 1, /**< Client Identifier Option. */
+ dhcp6_code_serverid = 2, /**< Server Identifier Option. */
+ dhcp6_code_ia_na = 3, /**< Identity Association for Non-temporary Addresses Option. */
+ dhcp6_code_ia_ta = 4, /**< Identity Association for Temporary Addresses Option. */
+ dhcp6_code_iaaddr = 5, /**< IA Address Option. */
+ dhcp6_code_oro = 6, /**< Option Request Option. */
+ dhcp6_code_preference = 7, /**< Preference Option. */
+ dhcp6_code_elapsed_time = 8, /**< Elapsed Time Option. */
+ dhcp6_code_relay_msg = 9, /**< Relay Message Option. */
+ dhcp6_code_auth = 11, /**< Authentication Option. */
+ dhcp6_code_unicast = 12, /**< Server Unicast Option. */
+ dhcp6_code_status_code = 13, /**< Status Code Option. */
+ dhcp6_code_rapid_commit = 14, /**< Rapid Commit Option. */
+ dhcp6_code_user_class = 15, /**< User Class Option. */
+ dhcp6_code_vendor_class = 16, /**< Vendor Class Option. */
+ dhcp6_code_vendor_opts = 17, /**< Vendor-specific Information Option. */
+ dhcp6_code_interface_id = 18, /**< Interface-Id Option. */
+ dhcp6_code_reconf_msg = 19, /**< Reconfigure Message Option. */
+ dhcp6_code_reconf_accept = 20, /**< Reconfigure Accept Option. */
+}
+tnet_dhcp6_option_code_t;
+
+/** List of DHCPv6 status codes as registered by IANA (RFC 3315 subclause 24.4) */
+typedef enum tnet_dhcp6_statuscode_e
+{
+ /* Success */
+ dhcp6_statuscode_Success = 0,
+ /* Failure, reason unspecified; this status code is sent by either a client
+ or a server to indicate a failure not explicitly specified in this document (RFC 3315). */
+ dhcp6_statuscode_UnspecFail = 1,
+ /* Server has no addresses available to assign to the IA(s). */
+ dhcp6_statuscode_NoAddrsAvail = 2,
+ /* Client record (binding) unavailable. */
+ dhcp6_statuscode_NoBinding = 3,
+ /* The prefix for the address is not appropriate for the link to which the client is attached. */
+ dhcp6_statuscode_NotOnLink = 4,
+ /* Sent by a server to a client to force the client to send messages to the server.
+ using the All_DHCP_Relay_Agents_and_Servers address.*/
+ dhcp6_statuscode_UseMulticast = 5
+}
+tnet_dhcp6_statuscode_t;
+
+/*=======================================================================================
+* RFC 3315 - 22.1. Format of DHCP Options
+*=======================================================================================*/
+
+/**@ingroup tnet_dhcpv_group
+* DHCPv6 option-data.
+*/
+typedef struct tnet_dhcp6_option_data_s
+{
+ TSK_DECLARE_OBJECT;
+}
+tnet_dhcp6_option_data_t;
+#define TNET_DECLARE_DHCP6_OPTION_DATA tnet_dhcp6_option_data_t dhcp6_option_data
+
+typedef struct tnet_dhcp6_option_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 3315 - 22.1. Format of DHCP Options
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | option-code(2) | option-len(2) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | option-data |
+ | (option-len octets) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ /* An unsigned integer identifying the specific option type carried in this option.*/
+ tnet_dhcp6_option_code_t code;
+ /* Option length. Same as tsk_strlen(data buffer)*/
+ uint16_t len;
+ /* opton-data */
+ tnet_dhcp6_option_data_t *data;
+}
+tnet_dhcp6_option_t;
+
+typedef tsk_list_t tnet_dhcp6_options_L_t;
+
+#define TNET_DECLARE_DHCP6_OPTION tnet_dhcp6_option_t dhcp6_option
+
+tnet_dhcp6_option_t* tnet_dhcp6_option_deserialize(const void* data, tsk_size_t size);
+int tnet_dhcp6_option_serialize(const tnet_dhcp6_option_t* self, tsk_buffer_t *output);
+int tnet_dhcp6_option_serializeex(tnet_dhcp6_option_code_t code, uint8_t length, const void* value, tsk_buffer_t *output);
+
+
+
+
+/*======================================================================================
+* RFC 3315 -
+ 22.2. Client Identifier Option
+ 22.3. Server Identifier Option
+*=======================================================================================*/
+/** DHCPv6 Client /server Identifier Option (subclause 22.2 and 22.3).
+*/
+typedef struct tnet_dhcp6_option_identifier_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_XXXXXXID | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . DUID .
+ . (variable length) .
+ . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ OPTION_XXXXXXID = OPTION_CLIENTID or OPTION_SERVERID
+ */
+ tnet_dhcp6_duid_t *duid;
+}
+tnet_dhcp6_option_identifier_t;
+typedef tnet_dhcp6_option_identifier_t tnet_dhcp6_option_clientid_t;
+typedef tnet_dhcp6_option_identifier_t tnet_dhcp6_option_serverid_t;
+
+
+/*======================================================================================
+* RFC 3315 - 22.4. Identity Association for Non-temporary Addresses Option
+*=======================================================================================*/
+
+/*======================================================================================
+* RFC 3315 - 22.7. Option Request Option
+*=======================================================================================*/
+
+/** DHCPv6 Option Request Option (subclause 22.7).
+*/
+typedef struct tnet_dhcp6_option_orequest_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_ORO | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | requested-option-code-1 | requested-option-code-2 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ tsk_buffer_t* codes;
+}
+tnet_dhcp6_option_orequest_t;
+
+TINYNET_API int tnet_dhcp6_option_orequest_add_code(tnet_dhcp6_option_orequest_t* self, uint16_t code);
+
+/*======================================================================================
+* RFC 3315 - 22.16. Vendor Class Option
+*=======================================================================================*/
+
+/** DHCPv6 Vendor Class Option (subclause 22.16).
+*/
+typedef struct tnet_dhcp6_option_vendorclass_s
+{
+ TNET_DECLARE_DHCP6_OPTION_DATA;
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | OPTION_VENDOR_CLASS | option-len |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | enterprise-number |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ . .
+ . vendor-class-data .
+ . . . . .
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ uint32_t enterprise_number;
+ /*
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
+ | vendor-class-len | opaque-data |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
+ */
+ tsk_buffer_t* vendor_class_data;
+}
+tnet_dhcp6_option_vendorclass_t;
+
+
+TINYNET_API tnet_dhcp6_option_t* tnet_dhcp6_option_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_indentifer_create(tnet_dhcp6_option_code_t code, const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_clientid_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_identifier_t* tnet_dhcp6_option_serverid_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_orequest_t* tnet_dhcp6_option_orequest_create_null();
+TINYNET_API tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create(const void* payload, tsk_size_t payload_size);
+TINYNET_API tnet_dhcp6_option_vendorclass_t* tnet_dhcp6_option_vendorclass_create_null();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_identifier_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_orequest_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dhcp6_option_vendorclass_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DHCP6_OPTION_H */
diff --git a/tinyNET/src/dns/tnet_dns.c b/tinyNET/src/dns/tnet_dns.c
new file mode 100644
index 0000000..0683cbb
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns.c
@@ -0,0 +1,973 @@
+/*
+* 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_dns.c
+ * @brief DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404] [3761]).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns.h"
+
+#include "tnet_dns_regexp.h"
+#include "tnet_dns_message.h"
+#include "tnet_dns_opt.h"
+#include "tnet_dns_srv.h"
+#include "tnet_dns_naptr.h"
+
+#include "tnet_types.h"
+
+#include "tsk_memory.h"
+#include "tsk_time.h"
+#include "tsk_debug.h"
+#include "tsk_string.h"
+
+#include <string.h> /* tsk_strlen, memser, .... */
+#include <ctype.h> /* isdigist */
+
+/* DNS cache functions */
+int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx);
+int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response);
+const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+
+/**@defgroup tnet_dns_group DNS utility functions (RFCS [1034 1035] [3401 3402 3403 3404]).
+*
+* <h1>11 DNS</h1>
+* <p>
+* The DNS Stack (RFC 1034 and RFC 1035) contains all network functions to send queries (both IPv4 and IPv6) and parse responses. <br>
+* The core framework implements RFC 3401, 3402, 3403 and 3404, also known as Dynamic Delegation Discovery System (DDDS).
+* </p>
+* <p>
+* The DNS servers are automatically loaded by the stack when you create a context (@ref tnet_dns_ctx_create()). <br>
+* On Windows systems (XP, VISTA, 7 and CE) the servers are retrieved using WIN32 APIs. On Unix-like systems (both desktop and embedded) such as Debian, Ubuntu, Nokia’s N900… the list of DNS servers comes from “/etc/resolv.conf” file. <br>
+* On Google Android operating system, this file is missing and the DNS settings are stored in the shared memory. You can access this shared memory by using @a property_get() and @a property_set() function which are part of Bionic. <br>
+* In all cases, you can retrieve the DNS servers yourself (e.g. using java/C# Frameworks) and add them to the context using @ref tnet_dns_add_server().
+* </p>
+* <p>
+* DNS resolution is always performed in a synchronous manner and is thread-safe. For all DNS requests the default timeout value is 5 seconds (@ref TNET_DNS_TIMEOUT_DEFAULT).
+* The stack also implements the ENUM protocol (RFC 3761).
+* </p>
+*
+* <h2>11.1 Resource Records</h2>
+* The table below lists all DNS Resource Records (RR) for which we provide a parser.
+*
+* <table>
+* <tr><td>Code</td> <td>RFC</td> <td>Description</td> <td>Well-defined type</td></tr>
+* <tr><td>A</td> <td>RFC 1035</td> <td>IPv4 address</td> <td>tnet_dns_a_t</td></tr>
+* <tr><td>AAAA</td> <td>RFC 3596</td> <td>IPv6 address</td> <td>tnet_dns_aaaa_t</td></tr>
+* <tr><td>CNAME</td> <td>RFC 1035</td> <td>Canonical name</td> <td>tnet_dns_cname_t</td></tr>
+* <tr><td>MX</td> <td>RFC 2035</td> <td>Mail exchange</td> <td>tnet_dns_mx_t</td></tr>
+* <tr><td>NAPTR</td> <td>RFC 3403</td> <td>Naming Authority Pointer</td> <td>tnet_dns_naptr_t</td></tr>
+* <tr><td>NS</td> <td>RFC 1035</td> <td>Name Server</td> <td>tnet_dns_ns_t</td></tr>
+* <tr><td>OPT</td> <td>RFC 2671</td> <td>Option</td> <td>tnet_dns_opt_t</td></tr>
+* <tr><td>PTR</td> <td>RFC 1035</td> <td>Pointer record</td> <td>tnet_dns_ptr_t</td></tr>
+* <tr><td>SOA</td> <td>RFC1035</td> <td>Start Of Authority record</td> <td>tnet_dns_soa_t</td></tr>
+* <tr><td>SRV</td> <td>RFC 2782</td> <td>Service locator</td> <td>tnet_dns_srv_t</td></tr>
+* </table>
+*
+* Here is an example of how to use the DNS stack to perform DNS NAPTR resolution and print the result to the console.
+*
+* @code
+tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+tnet_dns_response_t *response = tsk_null;
+const tsk_list_item_t* item;
+const tnet_dns_rr_t* rr;
+
+if((response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_naptr)))
+{
+ if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+ TSK_DEBUG_INFO("We got a success response from the DNS server.");
+ // loop through the answers
+ tsk_list_foreach(item, response->Answers){
+ rr = item->data;
+ if(rr->qtype == qtype_naptr){
+ const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
+
+ TSK_DEBUG_INFO("order=%u pref=%u flags=%s services=%s regexp=%s replacement=%s",
+ naptr->order,
+ naptr->preference,
+ naptr->flags,
+ naptr->services,
+ naptr->regexp,
+ naptr->replacement);
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
+ }
+}
+
+TSK_OBJECT_SAFE_FREE(response);
+TSK_OBJECT_SAFE_FREE(ctx);
+
+* @endcode
+* The @a ctx could be used several times and is a well-defined object.<br>
+* The console will output:
+* <i>INFO: We got a success response from the DNS server.</i><br>
+* <i>INFO: order=10 pref=0 flags=S services=SIP+d2u regexp=(null) replacement=_sip._udp.sip2sip.info</i><br>
+*
+* <h2>11.2 ENUM</h2>
+* ENUM (E.164 Number Mapping) protocol has been defined in RFC 3761.
+* ENUM protocol is used to transform telephone numbers of the PSTN network (e.g. +33600000) into internet resource addresses (e.g. sip:diopmamadou@example.com) by using DNS lookup (NAPTR). The internet resource address could be an email, ICQ, IAX2, H.323 …
+* In our case (3GPP IMS) it is typically used to convert TEL URIs (e.g. tel:+33600000) into SIP URIs (sip:+33600000;user=phone). The telephone number to convert should be a valid E.164 number.
+*
+* <h3>11.2.1 Usage</h3>
+* The code below shows how to gets the SIP address (with the higher order) associated to an E.164 telephone number.
+*
+* @code
+tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+tnet_dns_response_t* response = tsk_null;
+char* uri = tsk_null;
+
+if((uri = tnet_dns_enum_2(ctx, "E2U+SIP", "+1-800-555-5555","e164.org"))){
+ TSK_DEBUG_INFO("URI=%s", uri);
+ TSK_FREE(uri);
+}
+else{
+ TSK_DEBUG_ERROR("ENUM(%s) failed", "+1-800-555-5555");
+}
+
+TSK_OBJECT_SAFE_FREE(response);
+TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*
+* Console Output:<br>
+* <i>INFO: URI=sip:16416418000-555-5555@sip.tollfreegateway.com</i><br>
+*
+* E2U+SIP is the name of SIP ENUM service assigned by the IANA. Any assigned service () could be used even if the associated addresse type isn’t a well-knonw internet address.
+* To get all internet addresses (email, IAX2, ICQ, H.323 …) associated to the telephone, use @ref tnet_dns_enum() instead of @ref tnet_dns_enum_2().
+*/
+
+/**@ingroup tnet_dns_group
+* Creates new DNS context.
+*/
+tnet_dns_ctx_t* tnet_dns_ctx_create()
+{
+ return tsk_object_new(tnet_dns_ctx_def_t);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS cache entry.
+*/
+tnet_dns_cache_entry_t* tnet_dns_cache_entry_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* answer)
+{
+ return tsk_object_new(tnet_dns_cache_entry_def_t, qname, qclass, qtype, answer);
+}
+
+
+/**@ingroup tnet_dns_group
+* Cleanup the internal DNS cache.
+* @param ctx The DNS context containing the cache to cleanup.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @retval Zero if succeeed and non-zero error code otherwise.
+*/
+int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx)
+{
+ if(ctx){
+ tsk_safeobj_lock(ctx);
+ tsk_list_clear_items(ctx->cache);
+ tsk_safeobj_unlock(ctx);
+
+ return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_dns_group
+* Sends DNS request over the network. The request will be sent each 500 milliseconds until @ref TNET_DNS_TIMEOUT_DEFAULT milliseconds is reached.
+* @param ctx The DNS context to use. The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param qname The domain name (e.g. google.com).
+* @param qclass The CLASS of the query.
+* @param qtype The type of the query.
+* @retval The DNS response. The @a answers in the @a response are already filtered.
+* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE() macro.
+* @sa @ref tnet_dns_query_srv, @ref tnet_dns_query_naptr_srv, @ref tnet_dns_enum.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* tnet_dns_response_t *response = tnet_dns_resolve(ctx, "sip2sip.info", qclass_in, qtype_srv);
+* TSK_OBJECT_SAFE_FREE(response);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+tnet_dns_response_t *tnet_dns_resolve(tnet_dns_ctx_t* ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+#if HAVE_DNS_H
+ struct sockaddr_storage result;
+ struct sockaddr *from;
+ uint32_t fromlen;
+ char buf[TNET_DNS_DGRAM_SIZE_DEFAULT];
+ int32_t ret;
+
+ tnet_dns_response_t *response = tsk_null;
+
+ tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
+ tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
+
+ tsk_safeobj_lock(ctx);
+
+ // First, try with IPv4
+ if(TNET_SOCKET_IS_VALID(localsocket4)){
+ if((ret = tnet_get_sockaddr(localsocket4->fd, &result))){
+ TNET_PRINT_LAST_ERROR("tnet_get_sockaddr() failed.");
+ goto ipv6;
+ }
+ from = (struct sockaddr *) &result;
+ fromlen = from->sa_len;
+
+ if ((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0) {
+ response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
+ goto done;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("dns_search_v4()");
+ }
+ }
+ipv6:
+ // Then, try with IPv6
+ if(TNET_SOCKET_IS_VALID(localsocket6)){
+ if((ret = tnet_get_sockaddr(localsocket6->fd, &result))){
+ TNET_PRINT_LAST_ERROR("tnet_get_sockaddr() failed.");
+ goto done;
+ }
+ from = (struct sockaddr *) &result;
+ fromlen = from->sa_len;
+
+ if((ret = dns_search(ctx->resolv_handle, qname, qclass, qtype, buf, TNET_DNS_DGRAM_SIZE_DEFAULT, from, &fromlen)) > 0){
+ response = tnet_dns_message_deserialize((uint8_t *) buf, ret);
+ goto done;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("dns_search_v6()");
+ }
+ }
+
+done:
+ tsk_safeobj_unlock(ctx);
+
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+
+ return response;
+#else
+ tsk_buffer_t *output = tsk_null;
+ tnet_dns_query_t* query = tnet_dns_query_create(qname, qclass, qtype);
+ tnet_dns_response_t *response = tsk_null;
+ tsk_bool_t from_cache = tsk_false;
+
+ /* Check validity */
+ if(!ctx || !query){
+ goto bail;
+ }
+
+ /* Is there any DNS Server? */
+ if(TSK_LIST_IS_EMPTY(ctx->servers)){
+ TSK_DEBUG_ERROR("Failed to load DNS Servers. You can add new DNS servers by using \"tnet_dns_add_server\".");
+ goto bail;
+ }
+
+ /* Cache maintenance */
+ if(!TSK_LIST_IS_EMPTY(ctx->cache)){
+ /* Only do maintenance if the cache is not empty */
+ tnet_dns_cache_maintenance(ctx);
+ }
+
+ /* Retrieve data from cache. */
+ if(ctx->caching){
+ const tnet_dns_cache_entry_t *entry = tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
+ if(entry){
+ response = tsk_object_ref(((tnet_dns_cache_entry_t*)entry)->response);
+ from_cache = tsk_true;
+ goto bail;
+ }
+ }
+
+ /* Set user preference */
+ query->Header.RD = ctx->recursion;
+
+ /* EDNS0 */
+ if(ctx->edns0){
+ tnet_dns_opt_t *rr_opt = tnet_dns_opt_create(TNET_DNS_DGRAM_SIZE_DEFAULT);
+ if(!query->Additionals){
+ query->Additionals = tsk_list_create();
+ }
+ tsk_list_push_back_data(query->Additionals, (void**)&rr_opt);
+ query->Header.ARCOUNT++;
+ }
+
+ /* Serialize and send to the server. */
+ if(!(output = tnet_dns_message_serialize(query))){
+ TSK_DEBUG_ERROR("Failed to serialize the DNS message.");
+ goto bail;
+ }
+
+ /* ============================ */
+ // Send and Recaive data
+ /* ============================ */
+ {
+ int ret = -1;
+ struct timeval tv;
+ fd_set set;
+ tnet_fd_t maxFD;
+ uint64_t timeout = 0;
+ tsk_list_item_t *item;
+ const tnet_address_t *address;
+ struct sockaddr_storage server;
+ tnet_socket_t *localsocket4 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv4);
+ tnet_socket_t *localsocket6 = tnet_socket_create(TNET_SOCKET_HOST_ANY, TNET_SOCKET_PORT_ANY, tnet_socket_type_udp_ipv6);
+ tsk_bool_t useIPv6 = TNET_SOCKET_IS_VALID(localsocket6);
+
+ tsk_safeobj_lock(ctx);
+
+ /* Check socket validity */
+ if(!TNET_SOCKET_IS_VALID(localsocket4)){
+ goto done;
+ }
+
+ /* Always wait 500ms before retransmission */
+ tv.tv_sec = 0;
+ tv.tv_usec = (500 * 1000);
+
+ do
+ {
+ //
+ // Send data (loop through all intefaces)
+ //
+ tsk_list_foreach(item, ctx->servers)
+ {
+ address = item->data;
+ if(!address->ip ||
+ (address->family != AF_INET && address->family != AF_INET6) ||
+ (address->family == AF_INET6 && !TNET_SOCKET_IS_VALID(localsocket6))){
+ continue;
+ }
+
+ if(tnet_sockaddr_init(address->ip, ctx->server_port, (address->family == AF_INET ? tnet_socket_type_udp_ipv4 : tnet_socket_type_udp_ipv6), &server)){
+ TSK_DEBUG_ERROR("Failed to initialize the DNS server address: \"%s\"", address->ip);
+ continue;
+ }
+
+ TSK_DEBUG_INFO("Sending DNS query to \"%s\"", address->ip);
+
+ if(address->family == AF_INET6){
+ if((ret = tnet_sockfd_sendto(localsocket6->fd, (const struct sockaddr*)&server, output->data, output->size))){
+ // succeed?
+ break;
+ }
+ }
+ else{
+ if((ret = tnet_sockfd_sendto(localsocket4->fd, (const struct sockaddr*)&server, output->data, output->size))){
+ // succeed?
+ break;
+ }
+ }
+ }
+
+ //
+ // Received data
+ //
+ /* First time? ==> set timeout value */
+ if(!timeout){
+ timeout = tsk_time_epoch() + ctx->timeout;
+ }
+
+ /* Set FDs */
+ FD_ZERO(&set);
+ FD_SET(localsocket4->fd, &set);
+ if(useIPv6){
+ FD_SET(localsocket6->fd, &set);
+ maxFD = TSK_MAX(localsocket4->fd, localsocket6->fd);
+ }
+ else{
+ maxFD = localsocket4->fd;
+ }
+
+ /* wait for response */
+ if((ret = select(maxFD+1, &set, NULL, NULL, &tv))<0){ /* Error */
+ TNET_PRINT_LAST_ERROR("Select failed.");
+ goto done;
+ }
+ else if(ret == 0){ /* timeout ==> do nothing */
+
+ }
+ else{ /* there is data to read */
+ tsk_size_t len = 0;
+ void* data = 0;
+ tnet_fd_t active_fd;
+
+ /* Find active file descriptor */
+ if(FD_ISSET(localsocket4->fd, &set)){
+ active_fd = localsocket4->fd;
+ }
+ else if(FD_ISSET(localsocket6->fd, &set)){
+ active_fd = localsocket4->fd;
+ }
+ else{
+ TSK_DEBUG_ERROR("FD_ISSET ==> Invalid file descriptor.");
+ continue;
+ }
+
+ /* Check how how many bytes are pending */
+ if((ret = tnet_ioctlt(active_fd, FIONREAD, &len))<0){
+ TSK_DEBUG_ERROR("tnet_ioctlt failed with error code:%d", tnet_geterrno());
+ goto done;
+ }
+
+ /* Receive pending data */
+ data = tsk_calloc(len, sizeof(uint8_t));
+ if((ret = tnet_sockfd_recv(active_fd, data, len, 0))<0){
+ TSK_FREE(data);
+
+ TSK_DEBUG_ERROR("tnet_sockfd_recv failed with error code:%d", tnet_geterrno());
+ goto done;
+ }
+
+ /* Parse the incoming response. */
+ response = tnet_dns_message_deserialize(data, (tsk_size_t)ret);
+ TSK_FREE(data);
+
+ if(response)
+ { /* response successfuly parsed */
+ if(query->Header.ID != response->Header.ID || !TNET_DNS_MESSAGE_IS_RESPONSE(response)){
+ /* Not same transaction id ==> continue*/
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+ else goto done;
+ }
+ }
+ }
+ while(timeout > tsk_time_epoch());
+
+done:
+ tsk_safeobj_unlock(ctx);
+
+ TSK_OBJECT_SAFE_FREE(localsocket4);
+ TSK_OBJECT_SAFE_FREE(localsocket6);
+ goto bail;
+ }
+
+
+bail:
+ TSK_OBJECT_SAFE_FREE(query);
+ TSK_OBJECT_SAFE_FREE(output);
+
+ /* Add the result to the cache. */
+ if(response){
+ if(!from_cache && ctx->caching){
+ tnet_dns_cache_entry_add(ctx, qname, qclass, qtype, response);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to contact the DNS server.");
+ }
+
+ return response;
+#endif
+}
+
+/**@ingroup tnet_dns_group
+* Gets list of URIs associated to this telephone number by using ENUM protocol (RFC 3761).
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
+* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
+* @retval The DNS response with NAPTR RRs. The @a answers in the @a response are already filtered.
+* MUST be destroyed using @a TSK_OBJECT_SAFE_FREE macro.
+* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum_2.
+*/
+tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain)
+{
+ char e164domain[255];
+ tnet_dns_response_t* ret = tsk_null;
+ tsk_size_t e164size;
+ int i, j; // must be signed
+
+ e164size = tsk_strlen(e164num);
+
+ if(!ctx || !e164num || !e164size){
+ goto bail;
+ }
+
+ if(e164size /* max=15 digits + ".e164.arpa" + '+' */>=(sizeof(e164domain)-1)){
+ TSK_DEBUG_ERROR("%s is an invalid E.164 number.", e164num);
+ goto bail;
+ }
+
+ memset(e164domain, '\0', sizeof(e164domain));
+
+ /* RFC 3761 - 2.4. Valid Databases
+ 1. Remove all characters with the exception of the digits. For
+ example, the First Well Known Rule produced the Key
+ "+442079460148". This step would simply remove the leading "+",
+ producing "442079460148".
+
+ 2. Put dots (".") between each digit. Example:
+ 4.4.2.0.7.9.4.6.0.1.4.8
+
+ 3. Reverse the order of the digits. Example:
+ 8.4.1.0.6.4.9.7.0.2.4.4
+
+ 4. Append the string ".e164.arpa" to the end. Example:
+ 8.4.1.0.6.4.9.7.0.2.4.4.e164.arpa
+
+ This domain-name is used to request NAPTR records which may contain
+ the end result or, if the flags field is blank, produces new keys in
+ the form of domain-names from the DNS.
+ */
+ for(i = e164size-1, j=0; i>=0; i--){
+ if(!isdigit(e164num[i])){
+ continue;
+ }
+ e164domain[j++] = e164num[i];
+ e164domain[j++] = '.';
+ }
+
+ // append domain name
+ if(domain){
+ memcpy( &e164domain[j], domain, ((tsk_strlen(domain) + j) >= sizeof(e164domain)-1) ? (sizeof(e164domain)-j-1) : tsk_strlen(domain) );
+ }
+ else{
+ memcpy(&e164domain[j], "e164.arpa", 9);
+ }
+
+ /* == Performs DNS (NAPTR) lookup == */
+ ret = tnet_dns_resolve(ctx, e164domain, qclass_in, qtype_naptr);
+
+bail:
+
+ return ret;
+}
+
+/**@ingroup tnet_dns_group
+* Gets the internate address associated to this telephone number by using ENUM protocol (RFC 3761).
+* Only terminale rules containing uris(flags="u") will be considered and the regex string will be executed on the original string for
+* substitution. <br>
+* <b> Parsing complex regexp will probably fail (99.99% chance). Please use @ref tnet_dns_enum if you want to use your own regexp parser. </b>
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param service The ENUM service (e.g. E2U+SIP).
+* @param e164num A valid E.164 number (e.g. +1-800-555-5555).
+* @param domain The domain name (e.g e164.arpa, e164.org, ...). If Null, default value is "e164.arpa" (IANA).
+* @retval The Internet address (SIP, email, ICQ, fax, ...) associated to this service.
+* MUST be freed using @a TSK_FREE macro.
+* @sa @ref tnet_dns_resolve, @ref tnet_dns_enum.
+*/
+char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain)
+{
+ tnet_dns_response_t* response;
+ const tsk_list_item_t* item;
+ char* ret = tsk_null;
+ const tnet_dns_rr_t* rr;
+
+ if((response = tnet_dns_enum(ctx, e164num, domain))){
+ if(TNET_DNS_RESPONSE_IS_SUCCESS(response)){
+ tsk_list_foreach(item, response->Answers){
+ rr = item->data;
+ if(rr->qtype == qtype_naptr){
+ const tnet_dns_naptr_t *naptr = (const tnet_dns_naptr_t*)rr;
+ /* RFC 3403 - 6.2 E164 Example
+ Both the ENUM [18] and URI Resolution [4] Applications use the 'u'
+ flag. This flag states that the Rule is terminal and that the output
+ is a URI which contains the information needed to contact that
+ telephone service.
+ */
+ if( tsk_striequals(naptr->flags, "u") && tsk_striequals(naptr->services, service)){
+ /* RFC 3403 - 4.1 Packet Format
+ The fields (replacement and regexp) are also mutually exclusive. If a record is
+ returned that has values for both fields then it is considered to
+ be in error and SHOULD be either ignored or an error returned.
+ */
+ if(naptr->regexp && naptr->replacement){
+ continue;
+ }
+
+ if((ret = tnet_dns_regex_parse(e164num, naptr->regexp))){
+ break;
+ }
+ }
+ }
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("We got an error response from the DNS server. Error code: %u", response->Header.RCODE);
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_dns_group
+* Performs DNS SRV resolution.
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create.
+* @param service The name of the service (e.g. SIP+D2U).
+* @param hostname The result containing an IP address or FQDN.
+* @param port The port associated to the result.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tnet_dns_resolve.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* char* hostname = 0;
+* tnet_port_t port = 0;
+*
+* if(!tnet_dns_query_srv(ctx, "_sip._udp.sip2sip.info", &hostname, &port)){
+* TSK_DEBUG_INFO("DNS SRV succeed ==> hostname=%s and port=%u", hostname, port);
+* }
+*
+* TSK_FREE(hostname);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port)
+{
+ tnet_dns_response_t *response;
+
+ if(!ctx){
+ return -1;
+ }
+
+ // tnet_dns_resolve is thread-safe
+ if((response = tnet_dns_resolve(ctx, service, qclass_in, qtype_srv)))
+ {
+ const tsk_list_item_t *item;
+ const tnet_dns_rr_t* rr;
+ tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
+ {
+ rr = item->data;
+ if(rr->qtype == qtype_srv){
+ const tnet_dns_srv_t *srv = (const tnet_dns_srv_t*)rr;
+
+ tsk_strupdate(hostname, srv->target);
+ *port = srv->port;
+ break;
+ }
+ }
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+
+ return (hostname && !tsk_strnullORempty(*hostname)) ? 0 : -2;
+}
+
+/**@ingroup tnet_dns_group
+* Performs DNS NAPTR followed by DNS SRV resolution.
+* @param ctx The DNS context.
+* The context contains the user's preference and should be created using @ref tnet_dns_ctx_create().
+* @param domain The Name of the domain (e.g. google.com).
+* @param service The name of the service (e.g. SIP+D2U).
+* @param hostname The result containing an IP address or FQDN. Should be Null.
+* @param port The port associated to the result.
+* @retval Zero if succeed and non-zero error code otherwise.
+* @sa @ref tnet_dns_resolve.
+*
+* @code
+* tnet_dns_ctx_t *ctx = tnet_dns_ctx_create();
+* char* hostname = tsk_null;
+* tnet_port_t port = 0;
+*
+* if(!tnet_dns_query_naptr_srv(ctx, "sip2sip.info", "SIP+D2U", &hostname, &port)){
+* TSK_DEBUG_INFO("DNS NAPTR+SRV succeed ==> hostname=%s and port=%u", hostname, port);
+* }
+*
+* TSK_FREE(hostname);
+* TSK_OBJECT_SAFE_FREE(ctx);
+* @endcode
+*/
+int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port)
+{
+ tnet_dns_response_t *response;
+
+ if(!ctx || !hostname){
+ TSK_DEBUG_ERROR("Invalid parameters.");
+ return -1;
+ }
+
+ /* reset (do not free the user supplied value). trying to free dummy value will cause access violation error ==> zero. */
+ *hostname = tsk_null;
+
+ // tnet_dns_resolve is thread-safe
+ if((response = tnet_dns_resolve(ctx, domain, qclass_in, qtype_naptr))){
+ const tsk_list_item_t *item;
+ const tnet_dns_rr_t* rr;
+
+ char* replacement = tsk_null; /* e.g. _sip._udp.example.com */
+ char* flags = tsk_null;/* e.g. S, A, AAAA, A6, U, P ... */
+
+ tsk_list_foreach(item, response->Answers) /* Already Filtered ==> Peek the first One */
+ {
+ rr = item->data;
+ if(rr->qtype == qtype_naptr){
+ tnet_dns_naptr_t *naptr = (tnet_dns_naptr_t*)rr;
+
+ if(tsk_striequals(service, naptr->services)){
+ tsk_strupdate(&replacement, naptr->replacement);
+ tsk_strupdate(&flags, naptr->flags);
+
+ break;
+ }
+ }
+ }
+
+ if(flags && replacement){
+ if(tsk_striequals(flags, "S")){
+ tnet_dns_query_srv(ctx, replacement, hostname, port);
+ }
+ else if(tsk_striequals(flags, "A") || tsk_striequals(flags, "AAAA") ||tsk_striequals(flags, "A6")){
+ TSK_DEBUG_WARN("Defaulting port value.");
+ tsk_strupdate(hostname, replacement);
+ *port = 5060;
+ }
+ else{
+ TSK_DEBUG_ERROR("DNS NAPTR query returned invalid falgs.");
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("DNS NAPTR query returned zero result.");
+ }
+
+ TSK_FREE(flags);
+ TSK_FREE(replacement);
+ }
+
+ TSK_OBJECT_SAFE_FREE(response);
+
+ return (hostname && *hostname && !tsk_strempty(*hostname)) ? 0 : -2;
+}
+
+// remove timedout entries
+int tnet_dns_cache_maintenance(tnet_dns_ctx_t *ctx)
+{
+
+ if(ctx)
+ {
+ tsk_list_item_t *item;
+ tsk_safeobj_lock(ctx);
+again:
+
+ tsk_list_foreach(item, ctx->cache)
+ {
+ // FIXME: ttl should be from RR::ttl
+ tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
+ if((entry ->epoch + ctx->cache_ttl) < tsk_time_epoch()){
+ tsk_list_remove_item_by_data(ctx->cache, entry);
+ goto again; /* Do not delete data while looping */
+ }
+ }
+
+ tsk_safeobj_unlock(ctx);
+
+ return 0;
+ }
+ return -1;
+}
+
+// add an entry to the cache
+int tnet_dns_cache_entry_add(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tnet_dns_response_t* response)
+{
+ int ret = -1;
+
+ if(ctx)
+ {
+ tnet_dns_cache_entry_t *entry;
+
+ tsk_safeobj_lock(ctx);
+
+ entry = 0;
+
+ /* Retrieve from cache */
+ entry = (tnet_dns_cache_entry_t*)tnet_dns_cache_entry_get(ctx, qname, qclass, qtype);
+
+ if(entry){
+ /* UPDATE */
+ TSK_OBJECT_SAFE_FREE(entry->response);
+ entry->response = tsk_object_ref(response);
+ entry->epoch = tsk_time_epoch();
+ ret = 0;
+ goto done;
+ }
+ else{
+ /* CREATE */
+ entry = tnet_dns_cache_entry_create(qname, qclass, qtype, response);
+ if(entry){
+ tsk_list_push_back_data(ctx->cache, (void**)&entry);
+ ret = 0;
+ goto done;
+ }
+ else{
+ ret = -2;
+ goto done;
+ }
+ }
+done:
+ tsk_safeobj_unlock(ctx);
+ }
+ return ret;
+}
+
+// get an entry from the cache
+const tnet_dns_cache_entry_t* tnet_dns_cache_entry_get(tnet_dns_ctx_t *ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ tnet_dns_cache_entry_t *ret = tsk_null;
+ if(ctx)
+ {
+ tsk_list_item_t *item;
+
+ tsk_safeobj_lock(ctx);
+
+ tsk_list_foreach(item, ctx->cache){
+ tnet_dns_cache_entry_t *entry = (tnet_dns_cache_entry_t*)item->data;
+ if(entry->qtype == qtype && entry->qclass == qclass && tsk_strequals(entry->qname, qname)){
+ ret = entry;
+ break;
+ }
+ }
+
+ tsk_safeobj_unlock(ctx);
+ }
+
+ return ret;
+}
+
+
+/**@ingroup tnet_dns_group
+* Adds new DNS server to the list of the list of servers to query.
+* @param ctx DNS context containing the user parameters. The new DNS server will be added to this context.
+* @param host The IP address (or FQDN) of the dns server to add to the server.
+* @retval zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host)
+{
+ tnet_address_t *address;
+
+ if(!ctx || !host){
+ return -1;
+ }
+
+ if(!ctx->servers){
+ ctx->servers = tsk_list_create();
+ }
+
+ if((address = tnet_address_create(host))){
+ address->family = tnet_get_family(host, TNET_DNS_SERVER_PORT_DEFAULT);
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(ctx->servers, (void**)&address);
+
+ return 0;
+ }
+
+ return -2;
+}
+
+//=================================================================================================
+// [[DNS CACHE ENTRY]] object definition
+//
+static tsk_object_t* tnet_dns_cache_entry_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_cache_entry_t *entry = self;
+ if(entry){
+ entry->qname = tsk_strdup(va_arg(*app, const char*));
+ entry->qclass = va_arg(*app, tnet_dns_qtype_t);
+ entry->qtype = va_arg(*app, tnet_dns_qtype_t);
+ entry->response = tsk_object_ref(va_arg(*app, tnet_dns_response_t*));
+
+ entry->epoch = tsk_time_epoch();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_cache_entry_dtor(tsk_object_t * self)
+{
+ tnet_dns_cache_entry_t *entry = self;
+ if(entry){
+ TSK_OBJECT_SAFE_FREE(entry->response);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_cache_entry_def_s =
+{
+ sizeof(tnet_dns_cache_entry_t),
+ tnet_dns_cache_entry_ctor,
+ tnet_dns_cache_entry_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_cache_entry_def_t = &tnet_dns_cache_entry_def_s;
+
+
+//=================================================================================================
+// [[DNS CONTEXT]] object definition
+//
+static tsk_object_t* tnet_dns_ctx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ctx_t *ctx = self;
+ if(ctx){
+ ctx->timeout = TNET_DNS_TIMEOUT_DEFAULT;
+ ctx->recursion = tsk_true;
+ ctx->edns0 = tsk_true;
+ ctx->caching = tsk_false;
+
+ ctx->cache_ttl = TNET_DNS_CACHE_TTL;
+
+ ctx->server_port = TNET_DNS_SERVER_PORT_DEFAULT;
+
+ /* Gets all dns servers. */
+ ctx->servers = tnet_get_addresses_all_dnsservers();
+ /* Creates empty cache. */
+ ctx->cache = tsk_list_create();
+
+#if HAVE_DNS_H
+ ctx->resolv_handle = dns_open(NULL);
+#endif
+
+ tsk_safeobj_init(ctx);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_ctx_dtor(tsk_object_t * self)
+{
+ tnet_dns_ctx_t *ctx = self;
+ if(ctx){
+ tsk_safeobj_deinit(ctx);
+
+ TSK_OBJECT_SAFE_FREE(ctx->servers);
+ TSK_OBJECT_SAFE_FREE(ctx->cache);
+
+#if HAVE_DNS_H
+ dns_free(ctx->resolv_handle);
+#endif
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ctx_def_s =
+{
+ sizeof(tnet_dns_ctx_t),
+ tnet_dns_ctx_ctor,
+ tnet_dns_ctx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ctx_def_t = &tnet_dns_ctx_def_s;
diff --git a/tinyNET/src/dns/tnet_dns.h b/tinyNET/src/dns/tnet_dns.h
new file mode 100644
index 0000000..0ff6290
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns.h
@@ -0,0 +1,125 @@
+/*
+* 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_dns.h
+ * @brief DNS utilities functions (RFCS [1034 1035] [2671] [3401 3402 3403 3404] [3761]).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DNS_H
+#define TNET_DNS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_message.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_safeobj.h"
+
+#if HAVE_DNS_H
+#include <dns.h>
+#endif
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_dns_group
+*/
+#define TNET_DNS_CACHE_TTL (15000 * 1000)
+
+/**@ingroup tnet_dns_group
+* Default timeout (in milliseconds) value for DNS queries.
+*/
+#define TNET_DNS_TIMEOUT_DEFAULT 5000 //(5 seconds)
+
+/**@ingroup tnet_dns_group
+* Maximum supported Dgram size to advertise using EDNS0.
+*/
+#define TNET_DNS_DGRAM_SIZE_DEFAULT 4096
+
+/**@ingroup tnet_dns_group
+*/
+#define TNET_DNS_SERVER_PORT_DEFAULT 53
+
+/**DNS cache entry.
+*/
+typedef struct tnet_dns_cache_entry_s
+{
+ TSK_DECLARE_OBJECT;
+
+ char* qname;
+ tnet_dns_qclass_t qclass;
+ tnet_dns_qtype_t qtype;
+
+ uint64_t epoch;
+
+ tnet_dns_response_t *response;
+}
+tnet_dns_cache_entry_t;
+typedef tsk_list_t tnet_dns_cache_entries_L_t;
+typedef tnet_dns_cache_entries_L_t tnet_dns_cache_t;
+
+/**DNS context.
+*/
+typedef struct tnet_dns_ctx_s
+{
+ TSK_DECLARE_OBJECT;
+
+ uint64_t timeout; /**< In milliseconds. Default: @ref TNET_DNS_TIMEOUT_DEFAULT. */
+ tsk_bool_t recursion; /**< Indicates whether to direct the name server to pursue the query recursively. Default: enabled.*/
+ tsk_bool_t edns0; /**< Indicates whether to enable EDNS0 (Extension Mechanisms for DNS) or not. This option will allow you to send DNS packet larger than 512 bytes. Default: enabled. */
+ tsk_bool_t caching; /**< Indicates whether to enable the DNS cache or not. Default: no. */
+
+ int32_t cache_ttl;
+
+ tnet_port_t server_port; /**< Default port (@a TNET_DNS_SERVER_PORT_DEFAULT)) */
+
+ tnet_dns_cache_t *cache;
+ tnet_addresses_L_t *servers;
+
+#if HAVE_DNS_H
+ dns_handle_t resolv_handle;
+#endif
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_dns_ctx_t;
+
+TINYNET_API int tnet_dns_cache_clear(tnet_dns_ctx_t* ctx);
+TINYNET_API tnet_dns_response_t* tnet_dns_resolve(tnet_dns_ctx_t* ctx, const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+TINYNET_API tnet_dns_response_t* tnet_dns_enum(tnet_dns_ctx_t* ctx, const char* e164num, const char* domain);
+TINYNET_API char* tnet_dns_enum_2(tnet_dns_ctx_t* ctx, const char* service, const char* e164num, const char* domain);
+TINYNET_API int tnet_dns_query_srv(tnet_dns_ctx_t *ctx, const char* service, char** hostname, tnet_port_t* port);
+TINYNET_API int tnet_dns_query_naptr_srv(tnet_dns_ctx_t *ctx, const char* domain, const char* service, char** hostname, tnet_port_t* port);
+
+TINYNET_API int tnet_dns_add_server(tnet_dns_ctx_t *ctx, const char* host);
+
+TINYNET_API tnet_dns_ctx_t* tnet_dns_ctx_create();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ctx_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cache_entry_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_H */
diff --git a/tinyNET/src/dns/tnet_dns_a.c b/tinyNET/src/dns/tnet_dns_a.c
new file mode 100644
index 0000000..f53e070
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_a.c
@@ -0,0 +1,106 @@
+/*
+* 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_dns_a.c
+ * @brief DNS Address record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_a.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/** Creates new DNS A Resource Record.
+*/
+tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_a_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS A]] object definition
+//
+static tsk_object_t* tnet_dns_a_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_a_t *a = self;
+ if(a){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ const uint8_t* rddata = (((uint8_t*)data) + offset);
+ //const uint8_t* dataEnd = (rddata + rdlength);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(a), qtype_a, qclass);
+ TNET_DNS_RR(a)->name = tsk_strdup(name);
+ TNET_DNS_RR(a)->rdlength = rdlength;
+ TNET_DNS_RR(a)->ttl = ttl;
+
+ if(rddata && rdlength && (rdlength == 4/* 32bits */)){
+ // ==> DESERIALIZATION
+ /* ADDRESS */
+ uint32_t address = tnet_htonl_2(rddata);
+ tsk_sprintf(&(a->address), "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid IPv4 address.");
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_a_dtor(tsk_object_t * self)
+{
+ tnet_dns_a_t *a = self;
+ if(a){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(a));
+
+ TSK_FREE(a->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_a_def_s =
+{
+ sizeof(tnet_dns_a_t),
+ tnet_dns_a_ctor,
+ tnet_dns_a_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_a_def_t = &tnet_dns_a_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_a.h b/tinyNET/src/dns/tnet_dns_a.h
new file mode 100644
index 0000000..19fb910
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_a.h
@@ -0,0 +1,61 @@
+/*
+* 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_dns_a.h
+ * @brief DNS Address record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_A_H
+#define TNET_DNS_RR_A_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+
+/**DNS A Resource Record.
+*/
+typedef struct tnet_dns_a_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.4.1. A RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ADDRESS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* address;
+}
+tnet_dns_a_t;
+
+TINYNET_API tnet_dns_a_t* tnet_dns_a_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_a_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_A_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_aaaa.c b/tinyNET/src/dns/tnet_dns_aaaa.c
new file mode 100644
index 0000000..ab1fa64
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_aaaa.c
@@ -0,0 +1,108 @@
+/*
+* 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_dns_aaaA.c
+ * @brief DNS IPv6 address record - RR - (RFC 3596).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_aaaa.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+
+/** Creates new DNS AAAA Resource Record.
+*/
+
+tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_aaaa_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS AAAA]] object definition
+//
+static tsk_object_t* tnet_dns_aaaa_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_aaaa_t *aaaa = self;
+ if(aaaa){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ const uint8_t* rddata = (((uint8_t*)data) + offset);
+ //const uint8_t* dataEnd = (rddata + rdlength);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(aaaa), qtype_aaaa, qclass);
+ TNET_DNS_RR(aaaa)->name = tsk_strdup(name);
+ TNET_DNS_RR(aaaa)->rdlength = rdlength;
+ TNET_DNS_RR(aaaa)->ttl = ttl;
+
+ if(rddata && rdlength && (rdlength == 16/* 128bits */)){
+ // ==> DESERIALIZATION
+ /* ADDRESS */
+ tsk_sprintf(&(aaaa->address), "%x:%x:%x:%x:%x:%x:%x:%x",
+ tnet_ntohs_2(&rddata[0]), tnet_ntohs_2(&rddata[2]), tnet_ntohs_2(&rddata[4]), tnet_ntohs_2(&rddata[6]),
+ tnet_ntohs_2(&rddata[8]), tnet_ntohs_2(&rddata[10]), tnet_ntohs_2(&rddata[12]), tnet_ntohs_2(&rddata[14]));
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid IPv6 address.");
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_aaaa_dtor(tsk_object_t * self)
+{
+ tnet_dns_aaaa_t *aaaa = self;
+ if(aaaa){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(aaaa));
+
+ TSK_FREE(aaaa->address);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_aaaa_def_s =
+{
+ sizeof(tnet_dns_aaaa_t),
+ tnet_dns_aaaa_ctor,
+ tnet_dns_aaaa_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_aaaa_def_t = &tnet_dns_aaaa_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_aaaa.h b/tinyNET/src/dns/tnet_dns_aaaa.h
new file mode 100644
index 0000000..73d5f3f
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_aaaa.h
@@ -0,0 +1,58 @@
+/*
+* 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_dns_aaaa.h
+ * @brief DNS IPv6 address record - RR - (RFC 3596).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_AAAA_H
+#define TNET_DNS_RR_AAAA_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/**DNS AAAA Resource Record.
+*/
+typedef struct tnet_dns_aaaa_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 3596 -
+ */
+ char* address;
+}
+tnet_dns_aaaa_t;
+
+tnet_dns_aaaa_t* tnet_dns_aaaa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_aaaa_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_AAAA_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_cname.c b/tinyNET/src/dns/tnet_dns_cname.c
new file mode 100644
index 0000000..507a713
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_cname.c
@@ -0,0 +1,97 @@
+/*
+* 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_dns_cname.c
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_cname.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS CNAME Resource Record.
+*/
+
+tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_cname_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+//=================================================================================================
+// [[DNS CNAME]] object definition
+//
+static tsk_object_t* tnet_dns_cname_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_cname_t *cname = self;
+ if(cname){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(cname), qtype_cname, qclass);
+ TNET_DNS_RR(cname)->name = tsk_strdup(name);
+ TNET_DNS_RR(cname)->rdlength = rdlength;
+ TNET_DNS_RR(cname)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* CNAME */
+ tnet_dns_rr_qname_deserialize(data, &(cname->cname), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_cname_dtor(tsk_object_t * self)
+{
+ tnet_dns_cname_t *cname = self;
+ if(cname){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(cname));
+
+ TSK_FREE(cname->cname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_cname_def_s =
+{
+ sizeof(tnet_dns_cname_t),
+ tnet_dns_cname_ctor,
+ tnet_dns_cname_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_cname_def_t = &tnet_dns_cname_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_cname.h b/tinyNET/src/dns/tnet_dns_cname.h
new file mode 100644
index 0000000..b41b159
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_cname.h
@@ -0,0 +1,63 @@
+/*
+* 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_dns_cname.h
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_CNAME_H
+#define TNET_DNS_RR_CNAME_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS CNAME Resource Record
+*/
+typedef struct tnet_dns_cname_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* 3.3.1. CNAME RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / CNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* cname;
+}
+tnet_dns_cname_t;
+
+tnet_dns_cname_t* tnet_dns_cname_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_cname_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_CNAME_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_message.c b/tinyNET/src/dns/tnet_dns_message.c
new file mode 100644
index 0000000..cc2c2e2
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_message.c
@@ -0,0 +1,364 @@
+/*
+* 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_dns_message.h
+ * @brief DNS Message holding RRs (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_message.h"
+
+#include "../tnet_utils.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@ingroup tnet_dns_group
+* Creates new DNS message.
+* @sa tnet_dns_message_create_null.
+*/
+tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery)
+{
+ return tsk_object_new(tnet_dns_message_def_t, qname, qclass, qtype, isquery);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS message.
+* @sa tnet_dns_message_create.
+*/
+tnet_dns_message_t* tnet_dns_message_create_null()
+{
+ return tnet_dns_message_create(tsk_null, qclass_any, qtype_any, tsk_false);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS response message.
+* @sa tnet_dns_query_create.
+*/
+tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ return tnet_dns_message_create(qname, qclass, qtype, tsk_false);
+}
+
+/**@ingroup tnet_dns_group
+* Creates new DNS query message.
+* @sa tnet_dns_response_create.
+*/
+tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype)
+{
+ return tnet_dns_message_create(qname, qclass, qtype, tsk_true);
+}
+
+/**@ingroup tnet_dns_group
+* Serializes a DNS message in binary data.
+* @param message The DNS message to seriablize.
+* @retval The binary buffer containong the message if succeed. Otherwise, @a tsk_null is returned.
+* @sa tnet_dns_message_deserialize.
+*/
+tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message)
+{
+ tsk_buffer_t* output = tsk_null;
+ uint16_t _2bytes;
+ tsk_list_item_t *item;
+
+ /* Check message validity */
+ if(!message){
+ goto bail;
+ }
+
+ /* Creates empty buffer */
+ output = tsk_buffer_create_null();
+
+ /* ==============================
+ * HEADER
+ */
+ //tsk_buffer_append(output, &(message->Header), sizeof(message->Header));
+
+ /* ID */
+ _2bytes = tnet_ntohs(message->Header.ID);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */
+ {
+ uint16_t temp, _2bytes = 0;
+
+ temp = message->Header.QR, temp <<= 15;
+ _2bytes |= temp;
+
+ temp = message->Header.OPCODE, temp <<= 11;
+ _2bytes |= temp;
+
+ temp = message->Header.AA, temp <<= 10;
+ _2bytes |= temp;
+
+ temp = message->Header.TC, temp <<= 9;
+ _2bytes |= temp;
+
+ temp = message->Header.RD, temp <<= 8;
+ _2bytes |= temp;
+
+ temp = message->Header.RA, temp <<= 7;
+ _2bytes |= temp;
+
+ temp = message->Header.Z, temp <<= 4;
+ _2bytes |= temp;
+
+ temp = message->Header.RCODE, temp <<= 4;
+ _2bytes |= temp;
+
+ _2bytes = tnet_ntohs(_2bytes);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ }
+ /* QDCOUNT */
+ _2bytes = tnet_ntohs(message->Header.QDCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* ANCOUNT */
+ _2bytes = tnet_ntohs(message->Header.ANCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* NSCOUNT */
+ _2bytes = tnet_ntohs(message->Header.NSCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* ARCOUNT */
+ _2bytes = tnet_ntohs(message->Header.ARCOUNT);
+ tsk_buffer_append(output, &(_2bytes), 2);
+
+
+ /* ==============================
+ * QUESTION
+ */
+ if(TNET_DNS_MESSAGE_IS_QUERY(message))
+ {
+ /* QNAME */
+ tnet_dns_rr_qname_serialize(message->Question.QNAME, output);
+ /* QTYPE */
+ _2bytes = tnet_ntohs(message->Question.QTYPE);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ /* QCLASS */
+ _2bytes = tnet_ntohs(message->Question.QCLASS);
+ tsk_buffer_append(output, &(_2bytes), 2);
+ }
+
+ /* ==============================
+ * ANSWERS
+ */
+ tsk_list_foreach(item, message->Answers)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+ /* ==============================
+ * AUTHORITIES
+ */
+ tsk_list_foreach(item, message->Authorities)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+ /* ==============================
+ * ADDITIONALS
+ */
+ tsk_list_foreach(item, message->Additionals)
+ {
+ tnet_dns_rr_serialize((tnet_dns_rr_t *)item->data, output);
+ }
+
+
+bail:
+ return output;
+}
+
+/**@ingroup tnet_dns_group
+* Deserialize a STUN message from binary data.
+* @param data A pointer to the binary data.
+* @param size The size of the bnary data buffer.
+* @retval @ref tnet_dns_message_t object if succeed or NULL otherwise.
+* @sa @ref tnet_dns_message_serialize.
+*/
+tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size)
+{
+ tnet_dns_message_t *message = 0;
+ uint8_t *dataPtr, *dataEnd, *dataStart;
+ uint16_t i;
+ tsk_size_t offset = 0;
+
+ if(!data || !size){
+ goto bail;
+ }
+
+ dataPtr = (uint8_t*)data;
+ dataStart = dataPtr;
+ dataEnd = (dataStart + size);
+
+ message = tnet_dns_message_create_null();
+
+ /* === HEADER ===*/
+ /* ID */
+ message->Header.ID = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* |QR| Opcode |AA|TC|RD|RA| Z | RCODE | */
+ {
+ uint16_t flags = tnet_ntohs_2(dataPtr);
+
+ message->Header.QR = (flags >> 15);
+ message->Header.OPCODE = ((flags >> 11) & 0x000F);
+ message->Header.AA = ((flags >> 10) & 0x0001);
+ message->Header.TC = ((flags >> 9) & 0x0001);
+ message->Header.RD = ((flags >> 8) & 0x0001);
+ message->Header.RA = ((flags >> 7) & 0x0001);
+ message->Header.Z = ((flags >> 4) & 0x0007);
+ message->Header.RCODE = (flags & 0x000F);
+
+ dataPtr += 2;
+ }
+ /* QDCOUNT */
+ message->Header.QDCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* ANCOUNT */
+ message->Header.ANCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* NSCOUNT */
+ message->Header.NSCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+ /* ARCOUNT */
+ message->Header.ARCOUNT = tnet_ntohs_2(dataPtr);
+ dataPtr += 2;
+
+ /* === Queries ===*/
+ offset = (dataPtr - dataStart);
+ for(i=0; i<message->Header.QDCOUNT; i++)
+ {
+ /* Do not need to parse queries in the response ==> silently ignore */
+ char* name = 0;
+ tnet_dns_rr_qname_deserialize(dataStart, &name, &offset); /* QNAME */
+ dataPtr+=offset;
+ dataPtr+=4, offset+=4; /* QTYPE + QCLASS */
+ TSK_FREE(name);
+ }
+ dataPtr = (dataStart + offset); /* TODO: remove ==> obly for debug tests */
+
+ /* === Answers ===*/
+ offset = (dataPtr - dataStart);
+ for(i=0; i<message->Header.ANCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (dataEnd-dataPtr), &offset);
+ if(rr){
+ if(!message->Answers){
+ message->Answers = tsk_list_create();
+ }
+ /* Push in descending order (useful for NAPTR and SRV records). */
+ tsk_list_push_descending_data(message->Answers, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+ /* === Authorities ===*/
+ offset = (dataPtr - dataStart);
+ for(i=0; i<message->Header.NSCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (dataEnd-dataPtr), &offset);
+ if(rr){
+ if(!message->Authorities){
+ message->Authorities = tsk_list_create();
+ }
+ tsk_list_push_back_data(message->Authorities, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+ /* === Additionals ===*/
+ offset = (dataPtr - dataStart);
+ for(i=0; i<message->Header.ARCOUNT; i++)
+ {
+ tnet_dns_rr_t* rr = tnet_dns_rr_deserialize(dataStart, (dataEnd-dataPtr), &offset);
+ if(rr){
+ if(!message->Additionals){
+ message->Additionals = tsk_list_create();
+ }
+ tsk_list_push_back_data(message->Additionals, (void**)&rr);
+ }
+ }
+ dataPtr = (dataStart + offset);
+
+
+bail:
+ return message;
+}
+
+//=================================================================================================
+// [[DNS MESSAGE]] object definition
+//
+static tsk_object_t* tnet_dns_message_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_message_t *message = self;
+ if(message){
+ static uint16_t __dnsmessage_unique_id = 0;
+
+ const char* qname = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ tnet_dns_qtype_t qtype = va_arg(*app, tnet_dns_qtype_t);
+ tsk_bool_t isquery = va_arg(*app, tsk_bool_t);
+
+ /* Create random ID. */
+ message->Header.ID = ++__dnsmessage_unique_id;
+
+ /* QR field ==> query (0) - response (1) */
+ message->Header.QR = isquery ? 0 : 1;
+
+ if(isquery){
+ /* QDCOUNT field ==> at least one question */
+ message->Header.QDCOUNT = 1;
+ }
+
+ if(qname){
+ message->Question.QNAME = tsk_strdup(qname);
+ message->Question.QTYPE = qtype;
+ message->Question.QCLASS = qclass;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_message_dtor(tsk_object_t * self)
+{
+ tnet_dns_message_t *message = self;
+ if(message){
+ TSK_FREE(message->Question.QNAME);
+
+ TSK_OBJECT_SAFE_FREE(message->Answers);
+ TSK_OBJECT_SAFE_FREE(message->Authorities);
+ TSK_OBJECT_SAFE_FREE(message->Additionals);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_message_def_s =
+{
+ sizeof(tnet_dns_message_t),
+ tnet_dns_message_ctor,
+ tnet_dns_message_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_message_def_t = &tnet_dns_message_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_message.h b/tinyNET/src/dns/tnet_dns_message.h
new file mode 100644
index 0000000..a474095
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_message.h
@@ -0,0 +1,209 @@
+/*
+* 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_dns_message.h
+ * @brief DNS Message holding RRs (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DNS_MESSAGE_H
+#define TNET_DNS_MESSAGE_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+#include "tsk_buffer.h"
+
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_MESSAGE_IS_RESPONSE
+* Checks whether the STUN message is a response or not(query).
+* @sa TNET_DNS_MESSAGE_IS_QUERY.
+*/
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_MESSAGE_IS_QUERY
+* Checks whether the STUN message is a query or not(response).
+* @sa TNET_DNS_MESSAGE_IS_RESPONSE.
+*/
+
+TNET_BEGIN_DECLS
+
+
+#define TNET_DNS_MESSAGE_IS_RESPONSE(message) ((message) && (message)->Header.QR == 1)
+#define TNET_DNS_MESSAGE_IS_QUERY(message) ((message) && (message)->Header.QR == 0)
+
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_RESPONSE_IS_SUCCESS
+* Checks whether the STUN message is a success response or not(error).
+* @sa TNET_DNS_RESPONSE_IS_ERROR.
+*/
+/**@ingroup tnet_dns_group
+* @def TNET_DNS_RESPONSE_IS_ERROR
+* Checks whether the STUN message is an error response or not(success).
+* @sa TNET_DNS_RESPONSE_IS_SUCCESS.
+*/
+#define TNET_DNS_RESPONSE_IS_SUCCESS(response) ((response) && (response)->Header.RCODE == rcode_noerror)
+#define TNET_DNS_RESPONSE_IS_ERROR(response) !TNET_DNS_RESPONSE_IS_SUCCESS(response)
+
+/**Response codes as per RFC 1035 subclause 4.1.1.
+*/
+typedef enum tnet_dns_rcode_e
+{
+ rcode_noerror = 0,
+ rcode_error_format = 1,
+ rcode_server_failure = 2,
+ rcode_error_name = 3,
+ rcode_notimplemented = 4,
+ rcode_refused = 5
+}
+tnet_dns_rcode_t;
+
+/**OPCODE defining the kind of query as per RFC 1035 subclause 4.1.1.
+*/
+typedef enum tnet_dns_opcode_e
+{
+ opcode_query = 0, /**< 0 a standard query (QUERY) */
+ opcode_iquery = 1, /**< 1 an inverse query (IQUERY) */
+ opcode_status = 2, /**< 2 a server status request (STATUS) */
+}
+tnet_dns_opcode_t;
+
+/** DNS message as per RFC 1035 subclause 4.
+*/
+typedef struct tnet_dns_message_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 1035 - 4.1. Format
+ +---------------------+
+ | Header |
+ +---------------------+
+ | Question | the question for the name server
+ +---------------------+
+ | Answer | RRs answering the question
+ +---------------------+
+ | Authority | RRs pointing toward an authority
+ +---------------------+
+ | Additional | RRs holding additional information
+ +---------------------+
+ */
+
+ /* RFC 1035 - 4.1.1. Header section format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ID |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QDCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ANCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | NSCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ARCOUNT |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ struct
+ {
+ uint16_t ID;
+ unsigned QR:1;
+ unsigned OPCODE:4; /* see @ref tnet_dns_opcode_t */
+ unsigned AA:1;
+ unsigned TC:1;
+ unsigned RD:1;
+ unsigned RA:1;
+ unsigned Z:3;
+ unsigned RCODE:4; /* see @ref tnet_dns_rcode_t */
+ uint16_t QDCOUNT;
+ uint16_t ANCOUNT;
+ uint16_t NSCOUNT;
+ uint16_t ARCOUNT;
+ }
+ Header;
+
+ /* RFc 1035 - 4.1.2. Question section format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / QNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QTYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | QCLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ struct
+ {
+ /** RFC 1035 - 4.1.2. Question section format
+ a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.*/
+ void* QNAME;
+ /** RFC 1035 - 4.1.2. Question section format
+ a two octet code which specifies the type of the query.
+ The values for this field include all codes valid for a
+ TYPE field, together with some more general codes which
+ can match more than one type of RR.*/
+ tnet_dns_qtype_t QTYPE;
+ /* RFC 1035 - 4.1.2. Question section format
+ a two octet code that specifies the class of the query.
+ For example, the QCLASS field is IN for the Internet.
+ */
+ tnet_dns_qclass_t QCLASS;
+ }
+ Question;
+
+ tnet_dns_rrs_L_t *Answers; /**< Filtered answers by priority. */
+ tnet_dns_rrs_L_t *Authorities;
+ tnet_dns_rrs_L_t *Additionals;
+}
+tnet_dns_message_t;
+
+typedef tsk_list_t tnet_dns_messages_L_t; /**< List of @ref tnet_dns_message_t elements. */
+typedef tnet_dns_message_t tnet_dns_query_t; /**< DNS Query messsage. */
+typedef tnet_dns_message_t tnet_dns_response_t; /**< DNS response message. */
+
+tsk_buffer_t* tnet_dns_message_serialize(const tnet_dns_message_t *message);
+tnet_dns_message_t* tnet_dns_message_deserialize(const uint8_t *data, tsk_size_t size);
+
+
+tnet_dns_message_t* tnet_dns_message_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype, tsk_bool_t isquery);
+tnet_dns_message_t* tnet_dns_message_create_null();
+tnet_dns_response_t* tnet_dns_response_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+tnet_dns_query_t* tnet_dns_query_create(const char* qname, tnet_dns_qclass_t qclass, tnet_dns_qtype_t qtype);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_message_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_MESSAGE_H */
+
+
diff --git a/tinyNET/src/dns/tnet_dns_mx.c b/tinyNET/src/dns/tnet_dns_mx.c
new file mode 100644
index 0000000..8537af7
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_mx.c
@@ -0,0 +1,99 @@
+/*
+* 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_dns_mx.c
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_mx.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS MX Resource Record.
+*/
+tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_mx_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS MX]] object definition
+//
+static tsk_object_t* tnet_dns_mx_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_mx_t *mx = self;
+ if(mx){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(mx), qtype_mx, qclass);
+ TNET_DNS_RR(mx)->name = tsk_strdup(name);
+ TNET_DNS_RR(mx)->rdlength = rdlength;
+ TNET_DNS_RR(mx)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* PREFERENCE */
+ mx->preference = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* EXCHANGE */
+ tnet_dns_rr_qname_deserialize(data, &(mx->exchange), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_mx_dtor(tsk_object_t * self)
+{
+ tnet_dns_mx_t *mx = self;
+ if(mx){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(mx));
+
+ TSK_FREE(mx->exchange);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_mx_def_s =
+{
+ sizeof(tnet_dns_mx_t),
+ tnet_dns_mx_ctor,
+ tnet_dns_mx_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_mx_def_t = &tnet_dns_mx_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_mx.h b/tinyNET/src/dns/tnet_dns_mx.h
new file mode 100644
index 0000000..1bc4f66
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_mx.h
@@ -0,0 +1,66 @@
+/*
+* 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_dns_mx.h
+ * @brief DNS Mail eXchange record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_MX_H
+#define TNET_DNS_RR_MX_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS MX Resource Record
+*/
+typedef struct tnet_dns_mx_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.9. MX RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / EXCHANGE /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ uint16_t preference;
+ char* exchange;
+}
+tnet_dns_mx_t;
+
+tnet_dns_mx_t* tnet_dns_mx_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_mx_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_MX_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_naptr.c b/tinyNET/src/dns/tnet_dns_naptr.c
new file mode 100644
index 0000000..4152734
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_naptr.c
@@ -0,0 +1,146 @@
+/*
+* 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_dns_naptr.c
+ * @brief DNS Naming Authority Pointer - RR - (RFC 3403).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_naptr.h"
+
+
+#include "../tnet_types.h"
+#include "./tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+
+/** Creates new DNS NAPTR Resource Record.
+*/
+tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_naptr_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+
+
+//=================================================================================================
+// [[DNS NAPTR]] object definition
+//
+static tsk_object_t* tnet_dns_naptr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_naptr_t *naptr = self;
+ if(naptr){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(naptr), qtype_naptr, qclass);
+ TNET_DNS_RR(naptr)->name = tsk_strdup(name);
+ TNET_DNS_RR(naptr)->rdlength = rdlength;
+ TNET_DNS_RR(naptr)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* ORDER */
+ naptr->order = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* PREFERENCE */
+ naptr->preference = tnet_ntohs_2(((uint8_t*)data) + offset);
+ offset += 2;
+ /* FLAGS */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->flags), &offset);
+ /* SERVICES */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->services), &offset);
+ /* REGEXP */
+ tnet_dns_rr_charstring_deserialize(data, &(naptr->regexp), &offset);
+ /* REPLACEMENT */
+ tnet_dns_rr_qname_deserialize(data, &(naptr->replacement), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_naptr_dtor(tsk_object_t * self)
+{
+ tnet_dns_naptr_t *naptr = self;
+ if(naptr){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(naptr));
+
+ TSK_FREE(naptr->flags);
+ TSK_FREE(naptr->services);
+ TSK_FREE(naptr->regexp);
+ TSK_FREE(naptr->replacement);
+ }
+ return self;
+}
+
+static int tnet_dns_naptr_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ const tnet_dns_rr_t* rr1 = obj1;
+ const tnet_dns_rr_t* rr2 = obj2;
+
+ if(rr1 && rr2 && (rr1->qtype==qtype_naptr) && (rr2->qtype==qtype_naptr)){
+ const tnet_dns_naptr_t* naptr1 = (tnet_dns_naptr_t*)rr1;
+ const tnet_dns_naptr_t* naptr2 = (tnet_dns_naptr_t*)rr2;
+
+ /* Compare orders. */
+ if(naptr1->order < naptr2->order){ /* Lowest order is tried first. */
+ return 1;
+ }
+ else if(naptr1->order > naptr2->order){
+ return -1;
+ }
+
+ /* Compare preference */
+ if(naptr1->order < naptr2->order){ /* Lowest preference is tried first. */
+ return 1;
+ }
+ else if(naptr1->order > naptr2->order){
+ return -1;
+ }
+
+ return 0;
+ }
+ else{
+ return -1;
+ }
+}
+
+static const tsk_object_def_t tnet_dns_naptr_def_s =
+{
+ sizeof(tnet_dns_naptr_t),
+ tnet_dns_naptr_ctor,
+ tnet_dns_naptr_dtor,
+ tnet_dns_naptr_cmp,
+};
+const tsk_object_def_t *tnet_dns_naptr_def_t = &tnet_dns_naptr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_naptr.h b/tinyNET/src/dns/tnet_dns_naptr.h
new file mode 100644
index 0000000..b601d49
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_naptr.h
@@ -0,0 +1,81 @@
+/*
+* 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_dns_naptr.h
+ * @brief DNS Naming Authority Pointer - RR - (RFC 3403).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_NAPTR_H
+#define TNET_DNS_RR_NAPTR_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+/** DNS NAPTR Resource Record
+*/
+typedef struct tnet_dns_naptr_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 3403 - 4.1 Packet Format
+
+ The packet format for the NAPTR record is as follows
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | ORDER |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | PREFERENCE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / FLAGS /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / SERVICES /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / REGEXP /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / REPLACEMENT /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ <character-string> and <domain-name> as used here are defined in RFC 1035.
+ */
+ uint16_t order;
+ uint16_t preference;
+ char* flags;
+ char* services;
+ char* regexp;
+ char* replacement;
+}
+tnet_dns_naptr_t;
+
+TINYNET_API tnet_dns_naptr_t* tnet_dns_naptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_naptr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_NAPTR_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_ns.c b/tinyNET/src/dns/tnet_dns_ns.c
new file mode 100644
index 0000000..9453cec
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ns.c
@@ -0,0 +1,96 @@
+/*
+* 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_dns_ns.c
+ * @brief DNS Name Server record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_ns.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "tnet_dns_rr.h"
+
+/** Creates new DNS NS Resource Record.
+*/
+tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_ns_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS NS]] object definition
+//
+static tsk_object_t* tnet_dns_ns_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ns_t *ns = self;
+ if(ns){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(ns), qtype_ns, qclass);
+ TNET_DNS_RR(ns)->name = tsk_strdup(name);
+ TNET_DNS_RR(ns)->rdlength = rdlength;
+ TNET_DNS_RR(ns)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* NSDNAME */
+ tnet_dns_rr_qname_deserialize(data, &(ns->nsdname), &offset);
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_ns_dtor(tsk_object_t * self)
+{
+ tnet_dns_ns_t *ns = self;
+ if(ns){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(ns));
+
+ TSK_FREE(ns->nsdname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ns_def_s =
+{
+ sizeof(tnet_dns_ns_t),
+ tnet_dns_ns_ctor,
+ tnet_dns_ns_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ns_def_t = &tnet_dns_ns_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_ns.h b/tinyNET/src/dns/tnet_dns_ns.h
new file mode 100644
index 0000000..66c4ff8
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ns.h
@@ -0,0 +1,63 @@
+/*
+* 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_dns_ns.h
+ * @brief DNS Name Server record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_NS_H
+#define TNET_DNS_RR_NS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+
+/** DNS NS Resource Record.
+*/
+typedef struct tnet_dns_ns_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.11. NS RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / NSDNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* nsdname;
+}
+tnet_dns_ns_t;
+
+TINYNET_API tnet_dns_ns_t* tnet_dns_ns_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ns_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_NS_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_opt.c b/tinyNET/src/dns/tnet_dns_opt.c
new file mode 100644
index 0000000..f5e2c57
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_opt.c
@@ -0,0 +1,91 @@
+/*
+* 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_dns_opt.c
+ * @brief DNS OPT pseudo-RR (RFC 2671).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_opt.h"
+
+
+
+/** Creates new DNS OPT Resource Record.
+*/
+tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_dns_opt_def_t, payload_size);
+}
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// [[DNS OPT]] object definition
+//
+static tsk_object_t* tnet_dns_opt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_opt_t *rr_opt = self;
+ if(rr_opt){
+ uint16_t payload_size = (uint16_t)va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(rr_opt), qtype_opt, qclass_any);
+
+ /*
+ NAME domain name empty (root domain)
+ TYPE u_int16_t OPT
+ CLASS u_int16_t sender's UDP payload size
+ TTL u_int32_t extended RCODE and flags
+ RDLEN u_int16_t describes RDATA
+ RDATA octet stream {attribute,value} pairs
+
+ */
+ TNET_DNS_RR(rr_opt)->qclass = payload_size;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_opt_dtor(tsk_object_t * self)
+{
+ tnet_dns_opt_t *rr_opt = self;
+ if(rr_opt){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(rr_opt));
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_opt_def_s =
+{
+ sizeof(tnet_dns_opt_t),
+ tnet_dns_opt_ctor,
+ tnet_dns_opt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_opt_def_t = &tnet_dns_opt_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_opt.h b/tinyNET/src/dns/tnet_dns_opt.h
new file mode 100644
index 0000000..8c0407b
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_opt.h
@@ -0,0 +1,54 @@
+/*
+* 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_dns_opt.h
+ * @brief DNS OPT pseudo-RR (RFC 2671).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_OPT_H
+#define TNET_DNS_RR_OPT_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS OPT Resource Record
+*/
+typedef struct tnet_dns_opt_s
+{
+ TNET_DECLARE_DNS_RR;
+}
+tnet_dns_opt_t;
+
+tnet_dns_opt_t* tnet_dns_opt_create(tsk_size_t payload_size);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_opt_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_OPT_H */
diff --git a/tinyNET/src/dns/tnet_dns_ptr.c b/tinyNET/src/dns/tnet_dns_ptr.c
new file mode 100644
index 0000000..a629b91
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ptr.c
@@ -0,0 +1,97 @@
+/*
+* 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_dns_ptr.c
+ * @brief DNS Pointer record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_ptr.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS PTR Resource Record.
+*/
+
+
+tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_ptr_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS PTR]] object definition
+//
+static tsk_object_t* tnet_dns_ptr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_ptr_t *ptr = self;
+ if(ptr){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(ptr), qtype_ptr, qclass);
+ TNET_DNS_RR(ptr)->name = tsk_strdup(name);
+ TNET_DNS_RR(ptr)->rdlength = rdlength;
+ TNET_DNS_RR(ptr)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* PTRDNAME */
+ tnet_dns_rr_qname_deserialize(data, &(ptr->ptrdname), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_ptr_dtor(tsk_object_t * self)
+{
+ tnet_dns_ptr_t *ptr = self;
+ if(ptr){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(ptr));
+
+ TSK_FREE(ptr->ptrdname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_ptr_def_s =
+{
+ sizeof(tnet_dns_ptr_t),
+ tnet_dns_ptr_ctor,
+ tnet_dns_ptr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_ptr_def_t = &tnet_dns_ptr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_ptr.h b/tinyNET/src/dns/tnet_dns_ptr.h
new file mode 100644
index 0000000..19e1882
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_ptr.h
@@ -0,0 +1,61 @@
+/*
+* 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_dns_ptr.h
+ * @brief DNS Pointer record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_PTR_H
+#define TNET_DNS_RR_PTR_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+
+/** DNS PTR Resource Record
+*/
+typedef struct tnet_dns_ptr_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.12. PTR RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / PTRDNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* ptrdname;
+}
+tnet_dns_ptr_t;
+
+tnet_dns_ptr_t* tnet_dns_ptr_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void*data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_ptr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_PTR_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_regexp.c b/tinyNET/src/dns/tnet_dns_regexp.c
new file mode 100644
index 0000000..e0e60d1
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_regexp.c
@@ -0,0 +1,508 @@
+
+/* #line 1 "./ragel/tnet_dns_regexp.rl" */
+/*
+* 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_dns_regexp.h
+ * @brief DNS Regex parser for NAPTR RR.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_regexp.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/* === Ragel state machine === */
+
+/* #line 77 "./ragel/tnet_dns_regexp.rl" */
+
+
+/**
+* Apply @a regexp to @a e164num.
+* @param e164num Original E.164 number supplied by the user (only digits or '+' are accepted).
+* @param regexp A <character-string> containing a substitution expression that is
+* applied to the original string held by the client in order to
+* construct the next domain name to lookup. Example: "!^.*$!sip:bob@doubango.org!i".
+* @retval The final Internet address. It's up to the caller to free the string.
+*/
+char* tnet_dns_regex_parse(const char* e164num, const char* regexp)
+{
+ char* ret = tsk_null;
+ char* prefix = tsk_null;
+ const char* tag_start;
+ tsk_size_t e164len;
+
+ // Ragel
+ int cs = 0;
+ const char *p = tag_start = regexp;
+ const char *pe;
+ const char *eof;
+
+
+/* #line 68 "./src/dns/tnet_dns_regexp.c" */
+static const char _tdns_machine_regexp_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 2,
+ 0, 1, 2, 0, 2, 2, 2, 0,
+ 2, 3, 0, 3, 3, 0, 2
+};
+
+static const char _tdns_machine_regexp_key_offsets[] = {
+ 0, 0, 1, 2, 5, 6, 7, 8,
+ 9, 10, 11, 13, 15, 17, 19, 21,
+ 23, 25, 26, 27
+};
+
+static const char _tdns_machine_regexp_trans_keys[] = {
+ 33, 94, 40, 46, 92, 40, 46, 42,
+ 41, 36, 33, 33, 92, 33, 92, 48,
+ 57, 33, 92, 33, 92, 40, 42, 36,
+ 40, 40, 105, 0
+};
+
+static const char _tdns_machine_regexp_single_lengths[] = {
+ 0, 1, 1, 3, 1, 1, 1, 1,
+ 1, 1, 2, 2, 0, 2, 2, 2,
+ 2, 1, 1, 0
+};
+
+static const char _tdns_machine_regexp_range_lengths[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0
+};
+
+static const char _tdns_machine_regexp_index_offsets[] = {
+ 0, 0, 2, 4, 8, 10, 12, 14,
+ 16, 18, 20, 23, 26, 28, 31, 34,
+ 37, 40, 42, 44
+};
+
+static const char _tdns_machine_regexp_trans_targs[] = {
+ 2, 0, 3, 0, 5, 15, 17, 4,
+ 5, 4, 6, 0, 7, 0, 8, 0,
+ 9, 0, 10, 0, 18, 12, 11, 18,
+ 12, 11, 13, 0, 18, 0, 14, 18,
+ 0, 14, 5, 16, 4, 9, 5, 4,
+ 5, 4, 19, 0, 0, 0
+};
+
+static const char _tdns_machine_regexp_trans_actions[] = {
+ 0, 0, 0, 0, 7, 1, 0, 1,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 10, 10, 10, 13,
+ 13, 13, 0, 0, 19, 0, 16, 5,
+ 0, 0, 3, 0, 0, 0, 3, 0,
+ 7, 1, 0, 0, 0, 0
+};
+
+static const int tdns_machine_regexp_start = 1;
+static const int tdns_machine_regexp_first_final = 18;
+static const int tdns_machine_regexp_error = 0;
+
+static const int tdns_machine_regexp_en_main = 1;
+
+
+/* #line 101 "./ragel/tnet_dns_regexp.rl" */
+
+ if(!e164num){
+ goto bail;
+ }
+
+ if(!regexp){
+ ret = tsk_strdup(e164num);
+ goto bail;
+ }
+
+ e164len = tsk_strlen(e164num);
+ pe = p + tsk_strlen(regexp);
+ eof = pe;
+
+
+/* #line 147 "./src/dns/tnet_dns_regexp.c" */
+ {
+ cs = tdns_machine_regexp_start;
+ }
+
+/* #line 116 "./ragel/tnet_dns_regexp.rl" */
+
+/* #line 154 "./src/dns/tnet_dns_regexp.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _tdns_machine_regexp_trans_keys + _tdns_machine_regexp_key_offsets[cs];
+ _trans = _tdns_machine_regexp_index_offsets[cs];
+
+ _klen = _tdns_machine_regexp_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tdns_machine_regexp_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ cs = _tdns_machine_regexp_trans_targs[_trans];
+
+ if ( _tdns_machine_regexp_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tdns_machine_regexp_actions + _tdns_machine_regexp_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 42 "./ragel/tnet_dns_regexp.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 46 "./ragel/tnet_dns_regexp.rl" */
+ {
+ TSK_PARSER_SET_STRING(prefix);
+ }
+ break;
+ case 2:
+/* #line 50 "./ragel/tnet_dns_regexp.rl" */
+ {
+ int len = (int)(p - tag_start);
+ if(len){
+ tsk_strncat(&ret, tag_start, len);
+ }
+ }
+ break;
+ case 3:
+/* #line 57 "./ragel/tnet_dns_regexp.rl" */
+ {
+ if(prefix){
+ int prefixlen = tsk_strlen(prefix);
+ tsk_strncat(&ret, e164num + prefixlen, (e164len - prefixlen));
+ }
+ }
+ break;
+/* #line 257 "./src/dns/tnet_dns_regexp.c" */
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ _out: {}
+ }
+
+/* #line 117 "./ragel/tnet_dns_regexp.rl" */
+
+ if( cs <
+/* #line 273 "./src/dns/tnet_dns_regexp.c" */
+18
+/* #line 118 "./ragel/tnet_dns_regexp.rl" */
+ ){
+ TSK_DEBUG_ERROR("regexp substitition failed.");
+ TSK_FREE(ret);
+ }
+
+bail:
+ TSK_FREE(prefix);
+
+ return ret;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+///*
+//* 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_dns_regexp.h
+// * @brief DNS Regex parser for NAPTR RR.
+// *
+// * @author Mamadou Diop <diopmamadou(at)doubango.org>
+// *
+// * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+// */
+//#include "tnet_dns_regexp.h"
+//
+//#include "tsk_debug.h"
+//#include "tsk_memory.h"
+//#include "tsk_string.h"
+//#include "tsk_list.h"
+//
+//#include <string.h>
+//
+//const tsk_object_def_t *group_def_t;
+//typedef tsk_list_t groups_L_t;
+//
+//#define CREATE_GROUP(id) tsk_object_new(group_def_t, (int)id)
+//typedef struct group_s
+//{
+// TSK_DECLARE_OBJECT;
+//
+// int id;
+// tsk_size_t start;
+// tsk_size_t end;
+//}
+//group_t;
+//
+///* === Ragel state machine === */
+//%%{
+// machine tdns_machine_regexp;
+//
+// action tag{
+// tag_start = p;
+// }
+//
+// action inc_index{
+// index++;
+// TSK_DEBUG_INFO("inc_index %d", index);
+// }
+//
+// action create_group{
+// if(curr_group){
+// TSK_OBJECT_SAFE_FREE(curr_group);
+// }
+// curr_group = CREATE_GROUP(++group_id);
+// curr_group->start = index;
+// TSK_DEBUG_INFO("Create groupe");
+// }
+//
+// action add_group{
+// curr_group->end = index;
+// tsk_list_push_back_data(groups, (void**)&curr_group);
+// TSK_DEBUG_INFO("Create groupe");
+// }
+//
+// # http://www.itu.int/itudoc/itu-t/workshop/enum/012_pp7.ppt
+// # The format is like this: !<regexp>!<string>!
+// # * 1. Match <regexp> on the original E.164 number
+// # * 2. Apply rewrite rule <string>
+// # * \n in <string> is replaced with group number 'n' in <regexp>
+// #
+//
+// # Match beginning
+// m_begin = "^" any* $inc_index;
+//
+// # Match end
+// m_end = "$";
+//
+// # Math any character
+// m_any_c = ".";
+//
+// # Match any number of any character
+// m_any_string = ".*" | ".+";
+//
+// # Grouping
+// group_n = "\\" digit+;
+// group_begin = "(" >create_group;
+// group_end = ")" >add_group;
+// group = group_begin<: any* :>group_end;
+//
+// # Escaped char
+// escaped_char = "\\" alpha;
+//
+// regexp =
+// m_begin<:
+// m_any_c | m_any_string | group
+// :>m_end;
+//
+// string = any*;
+//
+// main := "!"<: regexp :> "!" <: string :> "!";
+//}%%
+//
+///**
+//* Apply @a regexp to @a e164num.
+//* @param e164num Original E.164 number supplied by the user (only digits or '+' are accepted).
+//* @param regexp A <character-string> containing a substitution expression that is
+//* applied to the original string held by the client in order to
+//* construct the next domain name to lookup. Example: "!^.*$!sip:bob@doubango.org!i".
+//* @retval The final Internet address. It's up to the caller to free the string.
+//*/
+//char* tnet_dns_regex_parse(const char* e164num, const char* regexp)
+//{
+// char* ret = tsk_null;
+// groups_L_t* groups = tsk_list_create();
+// group_t* curr_group = tsk_null;
+// tsk_size_t index = 0;
+// int group_id = 0;
+//
+// // Ragel
+// int cs = 0;
+// const char *p = regexp;
+// const char *pe;
+// const char *eof;
+//
+// %%write data;
+//
+// if(!e164num){
+// goto bail;
+// }
+//
+// if(!regexp){
+// ret = tsk_strdup(e164num);
+// goto bail;
+// }
+//
+// pe = p + tsk_strlen(regexp);
+// eof = pe;
+//
+// %%write init;
+// %%write exec;
+//
+// if( cs < %%{ write first_final; }%% ){
+// TSK_DEBUG_ERROR("regexp substitition failed.");
+// TSK_FREE(ret);
+// }
+//
+//bail:
+// TSK_OBJECT_SAFE_FREE(groups);
+// if(curr_group){
+// TSK_OBJECT_SAFE_FREE(curr_group);
+// }
+//
+// return ret;
+//}
+//
+////=================================================================================================
+//// String object definition
+////
+//static tsk_object_t* group_create(tsk_object_t * self, va_list * app)
+//{
+// group_t *g = self;
+// if(g){
+// g->id = va_arg(*app, int);
+// }
+// return self;
+//}
+//
+//static tsk_object_t* group_destroy(tsk_object_t * self)
+//{
+// group_t *g = self;
+// if(g){
+// }
+//
+// return self;
+//}
+//
+//static int group_cmp(const tsk_object_t *_g1, const tsk_object_t *_g2)
+//{
+// const group_t *g1 = _g1;
+// const group_t *g2 = _g2;
+//
+// if(g1 && g22){
+// return (g1->id - g2->id);
+// }
+// else if(!g1 && !g2) return 0;
+// else return -1;
+//}
+//
+//static const tsk_object_def_t group_def_s =
+//{
+// sizeof(group_t),
+// group_create,
+// group_destroy,
+// group_cmp,
+//};
+//const tsk_object_def_t *group_def_t = &group_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_regexp.h b/tinyNET/src/dns/tnet_dns_regexp.h
new file mode 100644
index 0000000..371cc27
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_regexp.h
@@ -0,0 +1,41 @@
+/*
+* 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_dns_regexp.h
+ * @brief DNS Regexp parser for NAPTR RR.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_REGEX_H
+#define TNET_DNS_REGEX_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API char* tnet_dns_regex_parse(const char* e164num, const char* regexp);
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_REGEX_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.c b/tinyNET/src/dns/tnet_dns_resolvconf.c
new file mode 100644
index 0000000..887ecfc
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_resolvconf.c
@@ -0,0 +1,301 @@
+
+/* #line 1 "./ragel/tnet_dns_resolvconf.rl" */
+/*
+* 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_dns_resolvconf.c
+ * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_resolvconf.h"
+
+#include "tnet_utils.h"
+
+#include "dns/tnet_dns.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_ragel_state.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+
+/* === Ragel state machine === */
+
+/* #line 80 "./ragel/tnet_dns_resolvconf.rl" */
+
+
+/** Gets list of DNS servers from a conf file.
+* @param path Path of the conf file from which to retrieve the DNS servers.
+* should be @a "/etc/resolv.conf". You can adjust the value by modifying @ref TNET_RESOLV_CONF_PATH.<br>
+* If you are using <b>Android</b> and the resolv.conf file is missing, then run the following line in a command window: <br>
+* <i>ln -s /private/var/run/resolv.conf /etc/resolv.conf</i><br> If this fails, then try to manually add the file.
+* @retval List of DNS servers.
+*/
+tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path)
+{
+ tnet_addresses_L_t* servers = tsk_null;
+ tnet_ip_t ip;
+ const char* fullpath = path;
+ const char* tag_start;
+ FILE* fd;
+ char buf[4092];
+
+ // Ragel
+ int cs = 0;
+ const char *p;
+ const char *pe;
+ const char *eof;
+
+
+/* #line 74 "./src/dns/tnet_dns_resolvconf.c" */
+static const char _tdns_machine_resolvconf_actions[] = {
+ 0, 1, 0, 1, 1
+};
+
+static const char _tdns_machine_resolvconf_key_offsets[] = {
+ 0, 6, 7, 8, 11, 14, 14, 20,
+ 22, 25, 28, 31, 34, 37, 40, 43,
+ 46, 49, 50, 51, 54
+};
+
+static const char _tdns_machine_resolvconf_trans_keys[] = {
+ 10, 13, 32, 35, 78, 110, 32, 32,
+ 10, 13, 32, 10, 13, 32, 10, 13,
+ 32, 35, 78, 110, 10, 13, 32, 65,
+ 97, 32, 77, 109, 32, 69, 101, 32,
+ 83, 115, 32, 69, 101, 32, 82, 114,
+ 32, 86, 118, 32, 69, 101, 32, 82,
+ 114, 32, 32, 10, 13, 32, 32, 35,
+ 78, 110, 0
+};
+
+static const char _tdns_machine_resolvconf_single_lengths[] = {
+ 6, 1, 1, 3, 3, 0, 6, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 3, 4
+};
+
+static const char _tdns_machine_resolvconf_range_lengths[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+};
+
+static const char _tdns_machine_resolvconf_index_offsets[] = {
+ 0, 7, 9, 11, 15, 19, 20, 27,
+ 30, 34, 38, 42, 46, 50, 54, 58,
+ 62, 66, 68, 70, 74
+};
+
+static const char _tdns_machine_resolvconf_indicies[] = {
+ 1, 1, 2, 3, 4, 4, 0, 5,
+ 0, 5, 6, 7, 7, 8, 6, 7,
+ 7, 8, 9, 9, 1, 1, 5, 3,
+ 4, 4, 0, 7, 7, 3, 5, 10,
+ 10, 0, 5, 11, 11, 0, 5, 12,
+ 12, 0, 5, 13, 13, 0, 5, 14,
+ 14, 0, 5, 15, 15, 0, 5, 16,
+ 16, 0, 5, 17, 17, 0, 5, 18,
+ 18, 0, 19, 0, 19, 20, 22, 22,
+ 23, 21, 2, 3, 4, 4, 0, 0
+};
+
+static const char _tdns_machine_resolvconf_trans_targs[] = {
+ 1, 6, 20, 7, 8, 2, 3, 0,
+ 4, 5, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 19, 0, 4
+};
+
+static const char _tdns_machine_resolvconf_trans_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 3, 3
+};
+
+static const int tdns_machine_resolvconf_start = 0;
+static const int tdns_machine_resolvconf_first_final = 0;
+static const int tdns_machine_resolvconf_error = -1;
+
+static const int tdns_machine_resolvconf_en_main = 0;
+
+
+/* #line 105 "./ragel/tnet_dns_resolvconf.rl" */
+
+ if(tsk_strnullORempty(fullpath)){
+ fullpath = TNET_RESOLV_CONF_PATH;
+ }
+
+ /* Open the file and read all data */
+ if((fd = fopen(fullpath, "r"))){
+ int len = fread(buf, sizeof(uint8_t), sizeof(buf)-2, fd);
+ p = &buf[0];
+ pe = p + len + 1/*hack*/;
+ eof = pe;
+ fclose(fd);
+
+ buf[len] = '\n'; // hack to have perfect lines
+
+ servers = tsk_list_create();
+ }
+ else{
+#if ANDROID
+ TSK_DEBUG_INFO("Failed to open [%s]. But don't panic, we have detected that you are using Google Android System.\n"
+ "You should look at the Progammer's Guide for more information.\n If you are not using DNS functions, don't worry about this warning.",
+ fullpath);
+#else
+ TSK_DEBUG_ERROR("Failed to open %s.", fullpath);
+#endif
+ goto bail;
+ }
+
+
+/* #line 176 "./src/dns/tnet_dns_resolvconf.c" */
+ {
+ cs = tdns_machine_resolvconf_start;
+ }
+
+/* #line 134 "./ragel/tnet_dns_resolvconf.rl" */
+
+/* #line 183 "./src/dns/tnet_dns_resolvconf.c" */
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+_resume:
+ _keys = _tdns_machine_resolvconf_trans_keys + _tdns_machine_resolvconf_key_offsets[cs];
+ _trans = _tdns_machine_resolvconf_index_offsets[cs];
+
+ _klen = _tdns_machine_resolvconf_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _tdns_machine_resolvconf_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += ((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _tdns_machine_resolvconf_indicies[_trans];
+ cs = _tdns_machine_resolvconf_trans_targs[_trans];
+
+ if ( _tdns_machine_resolvconf_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _tdns_machine_resolvconf_actions + _tdns_machine_resolvconf_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+/* #line 47 "./ragel/tnet_dns_resolvconf.rl" */
+ {
+ tag_start = p;
+ }
+ break;
+ case 1:
+/* #line 51 "./ragel/tnet_dns_resolvconf.rl" */
+ {
+ int len = (int)(p - tag_start);
+ if(len && len<=sizeof(ip)){
+ tnet_address_t *address;
+ memset(ip, '\0', sizeof(ip));
+ memcpy(ip, tag_start, len);
+
+ address = tnet_address_create(ip);
+ address->family = tnet_get_family(ip, TNET_DNS_SERVER_PORT_DEFAULT);
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(servers, (void**)&address);
+ }
+ }
+ break;
+/* #line 277 "./src/dns/tnet_dns_resolvconf.c" */
+ }
+ }
+
+_again:
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ }
+
+/* #line 135 "./ragel/tnet_dns_resolvconf.rl" */
+
+ if( cs <
+/* #line 290 "./src/dns/tnet_dns_resolvconf.c" */
+0
+/* #line 136 "./ragel/tnet_dns_resolvconf.rl" */
+ ){
+ TSK_DEBUG_ERROR("Failed to parse %s.", fullpath);
+ TSK_OBJECT_SAFE_FREE(servers);
+ }
+
+bail:
+ return servers;
+}
+
+
diff --git a/tinyNET/src/dns/tnet_dns_resolvconf.h b/tinyNET/src/dns/tnet_dns_resolvconf.h
new file mode 100644
index 0000000..b13e092
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_resolvconf.h
@@ -0,0 +1,43 @@
+/*
+* 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_dns_resolvconf.h
+ * @brief Parser for "/etc/resolv.conf" file to retrive DNS servers.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RESOLVCONF_H
+#define TNET_DNS_RESOLVCONF_H
+
+#include "tinynet_config.h"
+
+#include "tnet_types.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API tnet_addresses_L_t * tnet_dns_resolvconf_parse(const char* path);
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RESOLVCONF_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_rr.c b/tinyNET/src/dns/tnet_dns_rr.c
new file mode 100644
index 0000000..ddf3682
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_rr.c
@@ -0,0 +1,452 @@
+/*
+* 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_dns_rr.c
+ * @brief DNS Resource Record (RFC 1034 and 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_rr.h"
+
+#include "tnet_dns_a.h"
+#include "tnet_dns_aaaa.h"
+#include "tnet_dns_cname.h"
+#include "tnet_dns_mx.h"
+#include "tnet_dns_naptr.h"
+#include "tnet_dns_ns.h"
+#include "tnet_dns_opt.h"
+#include "tnet_dns_ptr.h"
+#include "tnet_dns_soa.h"
+#include "tnet_dns_srv.h"
+#include "tnet_dns_txt.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+#include "tsk_string.h"
+
+#include <string.h> /* strtok, strlen ... */
+
+
+/** Creates a new DNS RR.
+*/
+
+tnet_dns_rr_t* tnet_dns_rr_create()
+{
+ return tsk_object_new(tnet_dns_rr_def_t);
+}
+
+/** Initializes any DNS RR (either NAPTR or SRV ...).
+* @param rr The DNS RR to initialize.
+* @param qtype The type of the RR.
+* @param qclass The class of the RR.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass)
+{
+ if(rr){
+ if(!rr->initialized){
+ rr->qtype = qtype;
+ rr->qclass = qclass;
+
+ rr->initialized = tsk_true;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+/** Deinitializes any DNS RR (either NAPTR or SRV ...).
+* @param rr The DNS RR to deinitialize.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_dns_rr_deinit(tnet_dns_rr_t *rr)
+{
+ if(rr){
+ if(rr->initialized){
+ TSK_FREE(rr->name);
+ TSK_FREE(rr->rpdata);
+
+ rr->initialized = tsk_false;
+ return 0;
+ }
+ return -2;
+ }
+ return -1;
+}
+
+/** Deserialize <character-string>.
+*/
+int tnet_dns_rr_charstring_deserialize(const void* data, char** charstring, tsk_size_t *offset)
+{
+ /* RFC 1035 - 3.3. Standard RRs
+ <character-string> is a single length octet followed by that number of characters.
+ <character-string> is treated as binary information, and can be up to 256 characters in
+ length (including the length octet).
+ */
+ uint8_t* dataPtr = (((uint8_t*)data)+ *offset);
+ uint8_t length = *dataPtr;
+
+ *charstring = tsk_strndup((const char*)(dataPtr + 1), length);
+ *offset += (1 + length);
+
+ return 0;
+}
+
+/** Deserializes a QName.
+*/
+int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset)
+{
+ /* RFC 1035 - 4.1.4. Message compression
+
+ The pointer takes the form of a two octet sequence:
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | 1 1| OFFSET |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ uint8_t* dataPtr = (((uint8_t*)data) + *offset);
+ unsigned usingPtr = 0; /* Do not change. */
+
+ while(*dataPtr){
+ usingPtr = ((*dataPtr & 0xC0) == 0xC0);
+
+ if(usingPtr){
+ tsk_size_t ptr_offset = (*dataPtr & 0x3F);
+ ptr_offset = ptr_offset << 8 | *(dataPtr+1);
+
+ *offset += 2;
+ return tnet_dns_rr_qname_deserialize(data, name, &ptr_offset);
+ }
+ else{
+ uint8_t length;
+
+ if(*name){
+ tsk_strcat(name, ".");
+ }
+
+ length = *dataPtr;
+ *offset+=1, dataPtr++;
+
+ tsk_strncat(name, (const char*)dataPtr, length);
+ *offset += length, dataPtr += length;
+ }
+ }
+
+ *offset+=1;
+
+ return 0;
+}
+
+//int tnet_dns_rr_qname_deserialize(const void* data, tsk_size_t size, char** name, tsk_size_t *offset)
+//{
+// /* RFC 1035 - 4.1.4. Message compression
+//
+// The pointer takes the form of a two octet sequence:
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// | 1 1| OFFSET |
+// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+// */
+// uint8_t* dataPtr = (((uint8_t*)data) + *offset);
+// uint8_t* dataEnd = (dataPtr + size);
+// unsigned usingPtr = 0; /* Do not change. */
+// unsigned islast = 0;
+//
+// while(!islast)
+// {
+// usingPtr = ((*dataPtr & 0xC0) == 0xC0);
+//
+// if(usingPtr)
+// {
+// uint8_t *Ptr;
+// uint16_t ptr_offset = (*dataPtr & 0x3F);
+// ptr_offset = ptr_offset << 8 | *(dataPtr+1);
+// Ptr = ((uint8_t*)data) + ptr_offset;
+//
+// tnet_qname_label_parse(Ptr, (dataEnd - Ptr), name, &islast);
+// *offset += 2, dataPtr += 2;
+// }
+// else
+// {
+// tsk_size_t length = tnet_qname_label_parse(dataPtr, size, name, &islast);
+// *offset += length, dataPtr += length;
+// }
+// }
+//
+// *offset += usingPtr ? 0 : 1;
+//
+// return 0;
+//}
+
+/** Serializes a QName.
+*/
+int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output)
+{
+ /*
+ QNAME a domain name represented as a sequence of labels, where
+ each label consists of a length octet followed by that
+ number of octets. The domain name terminates with the
+ zero length octet for the null label of the root. Note
+ that this field may be an odd number of octets; no
+ padding is used.
+
+ Example: "doubango.com" ==> 8doubango3comNULL
+ */
+ static uint8_t null = 0;
+
+ if(qname){
+ char* _qname = tsk_strdup(qname);
+ char* label = strtok(_qname, ".");
+
+ while(label){
+ uint8_t length = tsk_strlen(label);
+ tsk_buffer_append(output, &length, 1);
+ tsk_buffer_append(output, label, tsk_strlen(label));
+
+ label = strtok (tsk_null, ".");
+ }
+
+ TSK_FREE(_qname);
+ }
+
+ /* terminates domain name */
+ tsk_buffer_append(output, &null, 1);
+
+ return 0;
+}
+
+/** Deserializes a DNS RR.
+*/
+tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset)
+{
+ tnet_dns_rr_t *rr = tsk_null;
+ uint8_t* dataStart = (uint8_t*)data;
+ uint8_t* dataPtr = (dataStart + *offset);
+ //uint8_t* dataEnd = (dataPtr+size);
+ tnet_dns_qtype_t qtype;
+ tnet_dns_qclass_t qclass;
+ uint32_t ttl;
+ uint16_t rdlength;
+ char* qname = tsk_null;
+
+ /* Check validity */
+ if(!dataPtr || !size){
+ goto bail;
+ }
+
+ /* == Parse QNAME == */
+ tnet_dns_rr_qname_deserialize(dataStart, &qname, offset);
+ dataPtr = (dataStart + *offset);
+ /* == Parse QTYPE == */
+ qtype = (tnet_dns_qtype_t)tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+ /* == Parse QCLASS == */
+ qclass = (tnet_dns_qclass_t)tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+ /* == Parse TTL == */
+ ttl = tnet_htonl_2(dataPtr);
+ dataPtr += 4, *offset += 4;
+ /* == Parse RDLENGTH == */
+ rdlength = tnet_ntohs_2(dataPtr);
+ dataPtr += 2, *offset += 2;
+
+ switch(qtype){
+ case qtype_a:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_a_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_aaaa:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_aaaa_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_cname:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_cname_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_mx:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_mx_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_naptr:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_naptr_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_ns:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_ns_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_opt:
+ {
+ unsigned payload_size = qclass;
+ rr = (tnet_dns_rr_t *)tnet_dns_opt_create(payload_size);
+ break;
+ }
+
+ case qtype_ptr:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_ptr_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_soa:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_soa_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_srv:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_srv_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ case qtype_txt:
+ {
+ rr = (tnet_dns_rr_t *)tnet_dns_txt_create(qname, qclass, ttl, rdlength, dataStart, *offset);
+ break;
+ }
+
+ default:
+ {
+ TSK_DEBUG_ERROR("NOT IMPLEMENTED");
+ break;
+ }
+ }
+
+bail:
+ TSK_FREE(qname);
+
+ *offset += rdlength;
+ return rr;
+}
+
+/** Serializes a DNS RR.
+*/
+int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output)
+{
+ if(!rr || !output){
+ return -1;
+ }
+
+ /*=== NAME ===*/
+ {
+ tnet_dns_rr_qname_serialize(rr->name, output);
+ }
+
+ /*=== TYPE ===*/
+ {
+ uint16_t qtype = tnet_htons(rr->qtype);
+ tsk_buffer_append(output, &(qtype), 2);
+ }
+
+ /*=== CLASS ===*/
+ {
+ uint16_t qclass = tnet_htons(rr->qclass);
+ tsk_buffer_append(output, &(qclass), 2);
+ }
+
+ /*=== TTL ===*/
+ {
+ uint32_t ttl = tnet_htonl(rr->ttl);
+ tsk_buffer_append(output, &(ttl), 4);
+ }
+
+ /*=== RDLENGTH ===*/
+ {
+ uint16_t length = tnet_htons(rr->rdlength);
+ tsk_buffer_append(output, &(length), 2);
+ }
+
+ /*=== RDATA : Request never contains data
+ ===*/
+ if(!rr->rpdata){
+ goto done;
+ }
+
+ switch(rr->qtype){
+ case qtype_a:
+ case qtype_aaaa:
+ case qtype_cname:
+ case qtype_mx:
+ case qtype_naptr:
+ case qtype_ns:
+ case qtype_opt:
+ case qtype_ptr:
+ case qtype_soa:
+ case qtype_srv:
+ case qtype_txt:
+ default:
+ {
+ TSK_DEBUG_WARN("DNS Request should not contains RDATA (not supported).");
+ break;
+ }
+ }
+
+done:
+ return 0;
+}
+
+
+//=================================================================================================
+// [[DNS RR]] object definition
+//
+static tsk_object_t* tnet_dns_rr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_rr_t *rr = self;
+ if(rr){
+ tnet_dns_rr_init(rr, qtype_any, qclass_any);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_rr_dtor(tsk_object_t * self)
+{
+ tnet_dns_rr_t *rr = self;
+ if(rr){
+ tnet_dns_rr_deinit(rr);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_rr_def_s =
+{
+ sizeof(tnet_dns_rr_t),
+ tnet_dns_rr_ctor,
+ tnet_dns_rr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_rr_def_t = &tnet_dns_rr_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_rr.h b/tinyNET/src/dns/tnet_dns_rr.h
new file mode 100644
index 0000000..f3fcbc0
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_rr.h
@@ -0,0 +1,171 @@
+/*
+* 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_dns_rr.h
+ * @brief DNS Resource Record (RFCS 1034 and 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_DNS_RR_H
+#define TNET_DNS_RR_H
+
+#include "tinynet_config.h"
+
+#include "tsk_list.h"
+#include "tsk_buffer.h"
+
+/** @def TNET_DNS_RR
+* Converts any DNS RR to a pointer to @ref tnet_dns_rr_t.
+* @retval A pointer to @ref tnet_dns_rr_t object.
+*/
+TNET_BEGIN_DECLS
+
+#define TNET_DNS_RR(self) ((tnet_dns_rr_t*)(self))
+
+/** RFC 1035 - 3.2.2. TYPE values
+* @sa http://en.wikipedia.org/wiki/List_of_DNS_record_types
+*/
+typedef enum tnet_dns_qtype_e
+{
+ qtype_a = 1, /**< A 1 a host address */
+ qtype_ns = 2, /**< NS 2 an authoritative name server */
+ qtype_md = 3, /**< MD 3 a mail destination (Obsolete - use MX) */
+ qtype_mf = 4, /**< MF 4 a mail forwarder (Obsolete - use MX) */
+ qtype_cname = 5, /**< CNAME 5 the canonical name for an alias */
+ qtype_soa = 6, /**< SOA 6 marks the start of a zone of authority */
+ qtype_mb = 7, /**< MB 7 a mailbox domain name (EXPERIMENTAL) */
+ qtype_mg = 8, /**< MG 8 a mail group member (EXPERIMENTAL) */
+ qtype_mr = 9, /**< MR 9 a mail rename domain name (EXPERIMENTAL) */
+ qtype_null = 10, /**< NULL 10 a null RR (EXPERIMENTAL) */
+ qtype_wks = 11, /**< WKS 11 a well known service description */
+ qtype_ptr = 12, /**< PTR 12 a domain name pointer */
+ qtype_hinfo = 13, /**< HINFO 13 host information */
+ qtype_minfo = 14, /**< MINFO 14 mailbox or mail list information */
+ qtype_mx = 15, /**< MX 15 mail exchange */
+ qtype_txt = 16, /**< TXT 16 text strings */
+
+ qtype_aaaa = 28, /**< AAAA 28 IPv6 host address */
+
+ qtype_srv = 33, /**< SRV 33 Service locator */
+
+ qtype_naptr = 35, /**< NAPTR 35 Naming Authority Pointer */
+
+ qtype_opt = 41, /**< OPT 41 Option */
+
+ qtype_ipseckey = 45,/**< IPSECKEY 45 IPSEC Key */
+
+ qtype_spf = 99, /**< SPF 99 SPF record */
+
+ qtype_any = 255 /**< * 255 A request for all records (3.2.3. QTYPE values)*/
+}
+tnet_dns_qtype_t;
+
+/** RFC 1035 - 3.2.4. CLASS values
+*/
+typedef enum tnet_dns_qclass_e
+{
+ qclass_in = 1, /**< IN 1 the Internet */
+ qclass_ics = 2, /**< CS 2 the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
+ qclass_ch = 3, /**< CH 3 the CHAOS class */
+ qclass_hs = 4, /**< HS 4 Hesiod [Dyer 87] */
+
+ qclass_any = 255 /**< * 255 any class (3.2.5. QCLASS values) */
+}
+tnet_dns_qclass_t;
+
+/** RFC 1034 (3.6. Resource Records) and 1035 (3.2.1. Format)
+*/
+typedef struct tnet_dns_rr_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* RFC 1035 - 3.2.1. Format
+ 1 1 1 1 1 1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | |
+ / /
+ / NAME /
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TYPE |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | CLASS |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | TTL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RDLENGTH |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
+ / RDATA /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+
+ tsk_bool_t initialized;
+
+ /** An owner name, i.e., the name of the node to which this resource record pertains. */
+ char* name;
+
+ /** Two octets containing one of the RR TYPE codes. */
+ tnet_dns_qtype_t qtype;
+
+ /** Two octets containing one of the RR CLASS codes. */
+ tnet_dns_qclass_t qclass;
+
+ /** A 32 bit signed integer that specifies the time interval (seconds) that the resource record may be cached before the source
+ of the information should again be consulted.
+ Zero values are interpreted to mean that the RR can only be used for the transaction in progress, and should not be cached.
+ For example, SOA records are always distributed with a zero TTL to prohibit caching. Zero values can also be used for extremely volatile data. */
+ int32_t ttl;
+
+ /** An unsigned 16 bit integer that specifies the length in octets of the RDATA field. */
+ uint16_t rdlength;
+
+ /** A variable length string of octets that describes the resource.
+ The format of this information varies according to the TYPE and CLASS of the resource record.*/
+ void *rpdata;
+}
+tnet_dns_rr_t;
+
+#define TNET_DECLARE_DNS_RR tnet_dns_rr_t dns_rr
+
+typedef tsk_list_t tnet_dns_rrs_L_t; /**< List of @ref tnet_dns_rr_t elements. */
+
+int tnet_dns_rr_init(tnet_dns_rr_t *rr, tnet_dns_qtype_t qtype, tnet_dns_qclass_t qclass);
+int tnet_dns_rr_deinit(tnet_dns_rr_t *rr);
+
+int tnet_dns_rr_charstring_deserialize(const void* data, char** name, tsk_size_t *offset);
+
+int tnet_dns_rr_qname_deserialize(const void* data, char** name, tsk_size_t *offset);
+int tnet_dns_rr_qname_serialize(const char* qname, tsk_buffer_t* output);
+
+tnet_dns_rr_t* tnet_dns_rr_deserialize(const void* data, tsk_size_t size, tsk_size_t* offset);
+int tnet_dns_rr_serialize(const tnet_dns_rr_t* rr, tsk_buffer_t *output);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_rr_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_H */
diff --git a/tinyNET/src/dns/tnet_dns_soa.c b/tinyNET/src/dns/tnet_dns_soa.c
new file mode 100644
index 0000000..0b8be15
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_soa.c
@@ -0,0 +1,112 @@
+/*
+* 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_dns_soa.c
+ * @brief DNS Start Of Authority record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_soa.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_soa_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS SOA]] object definition
+//
+static tsk_object_t* tnet_dns_soa_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_soa_t *soa = self;
+ if(soa){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(soa), qtype_soa, qclass);
+ TNET_DNS_RR(soa)->name = tsk_strdup(name);
+ TNET_DNS_RR(soa)->rdlength = rdlength;
+ TNET_DNS_RR(soa)->ttl = ttl;
+
+ if(rdlength)
+ { // ==> DESERIALIZATION
+ /* MNAME */
+ tnet_dns_rr_qname_deserialize(data, &(soa->mname), &offset);
+ /* RNAME */
+ tnet_dns_rr_qname_deserialize(data, &(soa->rname), &offset);
+ /* SERIAL */
+ soa->serial = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* REFRESH */
+ soa->refresh = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* RETRY */
+ soa->retry = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* EXPIRE */
+ soa->expire = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* MINIMUM */
+ soa->minimum = tnet_htonl_2(((uint8_t*)data) + offset),
+ offset += 2;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_soa_dtor(tsk_object_t * self)
+{
+ tnet_dns_soa_t *soa = self;
+ if(soa){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(soa));
+
+ TSK_FREE(soa->mname);
+ TSK_FREE(soa->rname);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_soa_def_s =
+{
+ sizeof(tnet_dns_soa_t),
+ tnet_dns_soa_ctor,
+ tnet_dns_soa_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_soa_def_t = &tnet_dns_soa_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_soa.h b/tinyNET/src/dns/tnet_dns_soa.h
new file mode 100644
index 0000000..eb88989
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_soa.h
@@ -0,0 +1,82 @@
+/*
+* 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_dns_soa.h
+ * @brief DNS Start Of Authority record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_SOA_H
+#define TNET_DNS_RR_SOA_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+TNET_BEGIN_DECLS
+
+typedef struct tnet_dns_soa_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.13. SOA RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / MNAME /
+ / /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / RNAME /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | SERIAL |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | REFRESH |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | RETRY |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | EXPIRE |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ | MINIMUM |
+ | |
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* mname;
+ char* rname;
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+}
+tnet_dns_soa_t;
+
+tnet_dns_soa_t* tnet_dns_soa_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_soa_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_SOA_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_srv.c b/tinyNET/src/dns/tnet_dns_srv.c
new file mode 100644
index 0000000..2fc8f41
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_srv.c
@@ -0,0 +1,137 @@
+/*
+* 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_dns_srv.c
+ * @brief DNS SeRVice locator record - RR - (RFC 2782).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_srv.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS SRV Resource Record.
+*/
+tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_srv_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS SRV]] object definition
+//
+static tsk_object_t* tnet_dns_srv_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_srv_t *srv = self;
+ if(srv){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(srv), qtype_srv, qclass);
+ TNET_DNS_RR(srv)->name = tsk_strdup(name);
+ TNET_DNS_RR(srv)->rdlength = rdlength;
+ TNET_DNS_RR(srv)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* Priority */
+ srv->priority = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Weight */
+ srv->weight = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Port */
+ srv->port = tnet_ntohs_2(((uint8_t*)data) + offset),
+ offset += 2;
+ /* Target */
+ tnet_dns_rr_qname_deserialize(data, &(srv->target), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_srv_dtor(tsk_object_t * self)
+{
+ tnet_dns_srv_t *srv = self;
+ if(srv){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(srv));
+
+ TSK_FREE(srv->target);
+ }
+ return self;
+}
+
+static int tnet_dns_srv_cmp(const tsk_object_t *obj1, const tsk_object_t *obj2)
+{
+ const tnet_dns_rr_t* rr1 = obj1;
+ const tnet_dns_rr_t* rr2 = obj2;
+
+ if(rr1 && rr2 && (rr1->qtype==qtype_srv) && (rr2->qtype==qtype_srv)){
+ const tnet_dns_srv_t* srv1 = (tnet_dns_srv_t*)rr1;
+ const tnet_dns_srv_t* srv2 = (tnet_dns_srv_t*)rr2;
+
+ /* Compare priorities. */
+ if(srv1->priority < srv2->priority){ /* Lowest priority is tried first. */
+ return 1;
+ }
+ else if(srv1->priority > srv2->priority){
+ return -1;
+ }
+
+ /* Compare weight */
+ if(srv1->weight > srv2->weight){
+ return 1;
+ }
+ else if(srv1->weight < srv2->weight){
+ return -1;
+ }
+
+ return 0;
+ }
+ else{
+ return -1;
+ }
+}
+
+static const tsk_object_def_t tnet_dns_srv_def_s =
+{
+ sizeof(tnet_dns_srv_t),
+ tnet_dns_srv_ctor,
+ tnet_dns_srv_dtor,
+ tnet_dns_srv_cmp,
+};
+const tsk_object_def_t *tnet_dns_srv_def_t = &tnet_dns_srv_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_srv.h b/tinyNET/src/dns/tnet_dns_srv.h
new file mode 100644
index 0000000..1e04c5d
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_srv.h
@@ -0,0 +1,59 @@
+/*
+* 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_dns_srv.h
+ * @brief DNS SeRVice locator record - RR - (RFC 2782).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_SRV_H
+#define TNET_DNS_RR_SRV_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS SRV Resource Record
+*/
+typedef struct tnet_dns_srv_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ uint16_t priority;
+ uint16_t weight;
+ uint16_t port;
+ char* target;
+}
+tnet_dns_srv_t;
+
+tnet_dns_srv_t* tnet_dns_srv_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_srv_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_SRV_H */
+
diff --git a/tinyNET/src/dns/tnet_dns_txt.c b/tinyNET/src/dns/tnet_dns_txt.c
new file mode 100644
index 0000000..baabed9
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_txt.c
@@ -0,0 +1,96 @@
+/*
+* 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_dns_txt.c
+ * @brief DNS TeXT record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_dns_txt.h"
+
+#include "../tnet_types.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+/** Creates new DNS TXT Resource Record.
+*/
+
+tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset)
+{
+ return tsk_object_new(tnet_dns_txt_def_t, name, qclass, ttl, rdlength, data, offset);
+}
+
+//=================================================================================================
+// [[DNS TXT]] object definition
+//
+static tsk_object_t* tnet_dns_txt_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_dns_txt_t *txt = self;
+ if(txt){
+ const char* name = va_arg(*app, const char*);
+ tnet_dns_qclass_t qclass = va_arg(*app, tnet_dns_qclass_t);
+ uint32_t ttl = va_arg(*app, uint32_t);
+#if defined(__GNUC__)
+ uint16_t rdlength = (uint16_t)va_arg(*app, unsigned);
+#else
+ uint16_t rdlength = va_arg(*app, uint16_t);
+#endif
+ const void* data = va_arg(*app, const void*);
+ tsk_size_t offset = va_arg(*app, tsk_size_t);
+
+ /* init base */
+ tnet_dns_rr_init(TNET_DNS_RR(txt), qtype_txt, qclass);
+ TNET_DNS_RR(txt)->name = tsk_strdup(name);
+ TNET_DNS_RR(txt)->rdlength = rdlength;
+ TNET_DNS_RR(txt)->ttl = ttl;
+
+ if(rdlength){
+ // ==> DESERIALIZATION
+ /* TXT-DATA */
+ tnet_dns_rr_charstring_deserialize(data, &(txt->txt_data), &offset);
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_dns_txt_dtor(tsk_object_t * self)
+{
+ tnet_dns_txt_t *txt = self;
+ if(txt){
+ /* deinit base */
+ tnet_dns_rr_deinit(TNET_DNS_RR(txt));
+
+ TSK_FREE(txt->txt_data);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_dns_txt_def_s =
+{
+ sizeof(tnet_dns_txt_t),
+ tnet_dns_txt_ctor,
+ tnet_dns_txt_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_dns_txt_def_t = &tnet_dns_txt_def_s;
diff --git a/tinyNET/src/dns/tnet_dns_txt.h b/tinyNET/src/dns/tnet_dns_txt.h
new file mode 100644
index 0000000..69b7a74
--- /dev/null
+++ b/tinyNET/src/dns/tnet_dns_txt.h
@@ -0,0 +1,61 @@
+/*
+* 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_dns_txt.h
+ * @brief DNS TeXT record - RR - (RFC 1035).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_DNS_RR_TXT_H
+#define TNET_DNS_RR_TXT_H
+
+#include "tinynet_config.h"
+
+#include "tnet_dns_rr.h"
+
+
+TNET_BEGIN_DECLS
+
+/** DNS TXT Resource Record
+*/
+typedef struct tnet_dns_txt_s
+{
+ TNET_DECLARE_DNS_RR;
+
+ /* RFC 1035 - 3.3.14. TXT RDATA format
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ / TXT-DATA /
+ +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ char* txt_data;
+}
+tnet_dns_txt_t;
+
+tnet_dns_txt_t* tnet_dns_txt_create(const char* name, tnet_dns_qclass_t qclass, uint32_t ttl, uint16_t rdlength, const void* data, tsk_size_t offset);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_dns_txt_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_DNS_RR_TXT_H */
+
diff --git a/tinyNET/src/ice/tnet_ice.c b/tinyNET/src/ice/tnet_ice.c
new file mode 100644
index 0000000..59916d3
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice.c
@@ -0,0 +1,32 @@
+/*
+* 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_ice.c
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per 'draft-ietf-mmusic-ice-19' and 'draft-ietf-mmusic-ice-tcp-08'.
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_ice.h"
diff --git a/tinyNET/src/ice/tnet_ice.h b/tinyNET/src/ice/tnet_ice.h
new file mode 100644
index 0000000..0ac69ef
--- /dev/null
+++ b/tinyNET/src/ice/tnet_ice.h
@@ -0,0 +1,42 @@
+/*
+* 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_ice.h
+ * @brief Interactive Connectivity Establishment (ICE) implementation as per 'draft-ietf-mmusic-ice-19' and 'draft-ietf-mmusic-ice-tcp-08'.
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-19
+ * http://tools.ietf.org/html/draft-ietf-mmusic-ice-tcp-08
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_ICE_H
+#define TNET_ICE_H
+
+#include "../tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+
+TNET_END_DECLS
+
+#endif /* TNET_ICE_H */
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 */
+
diff --git a/tinyNET/src/tinynet.h b/tinyNET/src/tinynet.h
new file mode 100644
index 0000000..853cc17
--- /dev/null
+++ b/tinyNET/src/tinynet.h
@@ -0,0 +1,58 @@
+/*
+* 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 tinynet.h
+ * @brief API functions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TINYNET_H
+#define TNET_TINYNET_H
+
+/* === tinySAK === */
+#include "tsk.h"
+
+/* === tinyNET === */
+
+#include "tnet.h"
+#include "tnet_nat.h"
+#include "tnet_socket.h"
+#include "tnet_transport.h"
+
+#include "stun/tnet_stun.h"
+
+#include "dns/tnet_dns.h"
+#include "dns/tnet_dns_naptr.h"
+#include "dns/tnet_dns_regexp.h"
+#include "dns/tnet_dns_resolvconf.h"
+
+#include "dhcp/tnet_dhcp.h"
+#include "dhcp/tnet_dhcp_option_sip.h"
+
+#include "dhcp6/tnet_dhcp6.h"
+#include "dhcp6/tnet_dhcp6_option.h"
+
+
+#endif /* TNET_TINYNET_H */
+
diff --git a/tinyNET/src/tinynet_config.h b/tinyNET/src/tinynet_config.h
new file mode 100644
index 0000000..31259b8
--- /dev/null
+++ b/tinyNET/src/tinynet_config.h
@@ -0,0 +1,120 @@
+/*
+* 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 tinynet_config.h
+ * @brief Global configuration file.
+ *
+ * This file incude all your preferences or configuration. All specific configuration
+ * must be defined in this file. You must include this file in all your header files.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef _TINYNET_H_
+#define _TINYNET_H_
+
+#ifdef __SYMBIAN32__
+#undef _WIN32 /* Because of WINSCW */
+#endif
+
+/* Windows (XP/Vista/7/CE and Windows Mobile) macro definition.
+*/
+#if defined(WIN32)|| defined(_WIN32) || defined(_WIN32_WCE)
+# define TNET_UNDER_WINDOWS 1
+#endif
+
+/**@def TINYNET_API
+* Used on Windows and Sysbian systems to export public functions.
+*/
+#if !defined(__GNUC__) && defined(TINYNET_EXPORTS)
+# define TINYNET_API __declspec(dllexport)
+# define TINYNET_GEXTERN __declspec(dllexport)
+#elif !defined(__GNUC__) /*&& defined(TINYNET_IMPORTS)*/
+# define TINYNET_API __declspec(dllimport)
+# define TINYNET_GEXTERN __declspec(dllimport)
+#else
+# define TINYNET_API
+# define TINYNET_GEXTERN extern
+#endif
+
+/* Guards against C++ name mangling
+*/
+#ifdef __cplusplus
+# define TNET_BEGIN_DECLS extern "C" {
+# define TNET_END_DECLS }
+#else
+# define TNET_BEGIN_DECLS
+# define TNET_END_DECLS
+#endif
+
+#if defined(_MSC_VER)
+# define TNET_INLINE __forceinline
+#elif defined(__GNUC__) && !defined(__APPLE__)
+# define TNET_INLINE __inline
+#else
+# define TNET_INLINE
+#endif
+
+/* have poll()? */
+#if (_WIN32_WINNT>=0x0600) || (ANDROID) || defined(__APPLE__)
+# define TNET_HAVE_POLL 1
+#else
+# define TNET_HAVE_POLL 0
+#endif
+
+/* whether to use poll() */
+#if TNET_UNDER_WINDOWS
+# define TNET_USE_POLL 0 /* Do not use WSAPoll event if under Vista. */
+#else
+# define TNET_USE_POLL 1
+#endif
+
+#if defined(__APPLE__)
+# define HAVE_IFADDRS 1
+# define HAVE_DNS_H 1
+# define TNET_HAVE_SS_LEN 1
+# define TNET_HAVE_SA_LEN 1
+#else
+# define HAVE_IFADDRS 0
+# define HAVE_DNS_H 0
+# define TNET_HAVE_SS_LEN 0
+# define TNET_HAVE_SA_LEN 0
+#endif
+
+/* Used in TURN/STUN2 attributes. */
+#define TNET_SOFTWARE "IM-client/OMA1.0 doubango/v0.0.0"
+#define TNET_IANA_PEN 35368 /**< PEN number assigned by the IANA.
+ The list of assigned numbers could be found here http://www.iana.org/assignments/enterprise-numbers. */
+#define TNET_RESOLV_CONF_PATH "/etc/resolv.conf" /**< Path to "/resolv.conf". */
+
+#include <stdint.h>
+
+
+#ifdef HAVE_CONFIG_H
+# include "../config.h"
+#endif
+
+#endif /* _TINYNET_H_ */
+
+
diff --git a/tinyNET/src/tls/tnet_tls.c b/tinyNET/src/tls/tnet_tls.c
new file mode 100644
index 0000000..ea3ec28
--- /dev/null
+++ b/tinyNET/src/tls/tnet_tls.c
@@ -0,0 +1,486 @@
+/*
+* 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_tls.c
+ * @brief TLS utilitity functions, based on openssl.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_tls.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+#include "tsk_debug.h"
+#include "tsk_safeobj.h"
+#include "tsk_thread.h"
+
+#define TNET_CIPHER_LIST "AES128-SHA"
+
+#if TNET_HAVE_OPENSSL_H
+# include <openssl/ssl.h>
+#endif
+
+#define TNET_TLS_TIMEOUT 2000
+#define TNET_TLS_RETRY_COUNT 5
+
+typedef struct tnet_tls_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_fd_t fd;
+
+ /* certs */
+ char* tlsdir_cas; /* Trusted CAs directory. */
+ char* tlsfile_ca;
+ char* tlsfile_pvk;
+ char* tlsfile_pbk;
+ char* password; /* password for the private vkey */
+
+#if TNET_HAVE_OPENSSL_H
+ /* SSL */
+ SSL_METHOD *ssl_meth;
+ SSL_CTX *ssl_ctx;
+ SSL *ssl;
+#endif
+
+ unsigned initialized;
+ tsk_bool_t isClient;
+ tsk_bool_t mutual_auth;
+
+ TSK_DECLARE_SAFEOBJ;
+}
+tnet_tls_socket_t;
+
+
+tnet_tls_socket_handle_t* tnet_tls_socket_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk, tsk_bool_t isClient)
+{
+ return tsk_object_new(tnet_tls_socket_def_t, fd, tlsfile_ca, tlsfile_pvk, tlsfile_pbk, isClient);
+}
+
+tnet_tls_socket_handle_t* tnet_tls_socket_client_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk)
+{
+ return tnet_tls_socket_create(fd, tlsfile_ca, tlsfile_pvk, tlsfile_pbk, tsk_true);
+}
+
+tnet_tls_socket_handle_t* tnet_tls_socket_server_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk)
+{
+ return tnet_tls_socket_create(fd, tlsfile_ca, tlsfile_pvk, tlsfile_pbk, tsk_false);
+}
+
+
+int tnet_tls_socket_isok(const tnet_tls_socket_handle_t* self)
+{
+ if(!self){
+ return 0;
+ }
+ else return ((const tnet_tls_socket_t*)self)->initialized;
+}
+
+int tnet_tls_socket_connect(tnet_tls_socket_handle_t* self)
+{
+#if !TNET_HAVE_OPENSSL_H
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ tnet_tls_socket_t* socket;
+#if defined(DEBUG) || defined(_DEBUG)
+ X509* svr_cert;
+#endif
+
+ if(!self){
+ return -1;
+ }
+
+ socket = self;
+
+ if(!socket->initialized){
+ TSK_DEBUG_ERROR("TLS socket not properly initialized.");
+ return -2;
+ }
+
+ //ret = SSL_do_handshake(socket->ssl);
+ if((ret = SSL_connect(socket->ssl)) != 1){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ || ret == SSL_ERROR_SYSCALL){
+ ret = 0; /* Up to the caller to check that the socket is writable and valid. */
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_connect failed [%d].", ret);
+ //if(ret == SSL_ERROR_SYSCALL){
+ // TNET_PRINT_LAST_ERROR("SSL_connect returned SSL_ERROR_SYSCALL:");
+ //}
+ }
+ }
+ else ret = 0;
+
+#if defined(DEBUG) || defined(_DEBUG)
+ /* Print Server cert */
+ if((ret == 0) && (svr_cert = SSL_get_peer_certificate(socket->ssl))) {
+ TSK_DEBUG_INFO("Server cert - Subject: %s", X509_NAME_oneline(X509_get_subject_name(svr_cert), 0, 0));
+ TSK_DEBUG_INFO("Server cert - Issuer: %s", X509_NAME_oneline(X509_get_issuer_name(svr_cert), 0, 0));
+ X509_free(svr_cert);
+ }
+#endif
+
+ return ret;
+#endif
+}
+
+int tnet_tls_socket_write(tnet_tls_socket_handle_t* self, const void* data, tsk_size_t size)
+{
+#if !TNET_HAVE_OPENSSL_H
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ int rcount = TNET_TLS_RETRY_COUNT;
+ tnet_tls_socket_t* socket;
+
+ if(!self){
+ return -1;
+ }
+
+ socket = self;
+
+ if(!socket->initialized){
+ TSK_DEBUG_ERROR("TLS socket not properly initialized.");
+ return -2;
+ }
+
+ /* Write */
+ tsk_safeobj_lock(socket);
+ssl_write:
+ if(rcount && ((ret = SSL_write(socket->ssl, data, size)) <= 0)){
+ int want_read;
+ ret = SSL_get_error(socket->ssl, ret);
+ want_read = (ret == SSL_ERROR_WANT_READ);
+
+ if(ret == SSL_ERROR_WANT_WRITE || want_read){
+
+ if(!(ret = tnet_sockfd_waitUntil(socket->fd, TNET_TLS_TIMEOUT, !want_read))){
+ rcount--;
+
+ if(want_read && !SSL_is_init_finished(socket->ssl)){
+ tsk_thread_sleep(200); // FIXME
+ }
+ goto ssl_write;
+ }
+
+ //if(ret == SSL_ERROR_WANT_READ){
+ // if(!SSL_is_init_finished(socket->ssl)){
+ // tsk_size_t size = 1024;
+ // char* buffer = tsk_calloc(size, sizeof(uint8_t));
+ // int isEncrypted = 1;
+ //
+ // // read()
+ // tsk_safeobj_unlock(socket);
+ // tnet_tls_socket_recv(socket, &buffer, &size, &isEncrypted);
+ // TSK_FREE(buffer);
+ // tsk_safeobj_lock(socket);
+ // }
+ // rcount--;
+ // goto ssl_write;
+ //}
+ //else{
+ // if(!(ret = tnet_sockfd_waitUntilWritable(socket->fd, TNET_TLS_TIMEOUT))){
+ // rcount--;
+ // goto ssl_write;
+ // }
+ // else goto bail;
+ //}
+
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_write failed [%d].", ret);
+ ret = -3;
+ }
+ }
+ tsk_safeobj_unlock(socket);
+
+//bail:
+ ret = (ret > 0) ? 0 : -3;
+ return ret;
+#endif
+}
+
+int tnet_tls_socket_recv(tnet_tls_socket_handle_t* self, void** data, tsk_size_t *size, int *isEncrypted)
+{
+#if !TNET_HAVE_OPENSSL_H
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+ tsk_size_t read = 0;
+ tsk_size_t to_read = *size;
+ int rcount = TNET_TLS_RETRY_COUNT;
+ tnet_tls_socket_t* socket;
+
+ if(!self){
+ return -1;
+ }
+
+ socket = self;
+
+ if(!socket->initialized){
+ TSK_DEBUG_ERROR("TLS socket not properly initialized.");
+ return -2;
+ }
+
+ tsk_safeobj_lock(socket);
+
+ *isEncrypted = SSL_is_init_finished(socket->ssl) ? 0 : 1;
+
+ /* SSL handshake has completed? */
+ if(*isEncrypted){
+ char* buffer[1024];
+ if((ret = SSL_read(socket->ssl, buffer, 1024)) <= 0){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){
+ ret = 0;
+ }
+ *size = 0;
+ }
+ else{
+ *size = ret;
+ ret = 0;
+ }
+
+ goto bail;
+ }
+
+ /* Read Application data */
+ssl_read:
+ if(rcount && ((ret = SSL_read(socket->ssl, (((uint8_t*)*data)+read), to_read)) <= 0)){
+ ret = SSL_get_error(socket->ssl, ret);
+ if(ret == SSL_ERROR_WANT_WRITE || ret == SSL_ERROR_WANT_READ){
+ if(!(ret = tnet_sockfd_waitUntil(socket->fd, TNET_TLS_TIMEOUT, (ret == SSL_ERROR_WANT_WRITE)))){
+ rcount--;
+ goto ssl_read;
+ }
+ }
+ else if(SSL_ERROR_ZERO_RETURN){ /* connection closed: do nothing, the transport layer will be alerted. */
+ *size = ret;
+ ret = 0;
+ TSK_DEBUG_INFO("TLS connection closed.");
+ }
+ else{
+ TSK_DEBUG_ERROR("SSL_read failed [%d].", ret);
+ }
+ }
+ else if(ret >=0){
+ read += (tsk_size_t)ret;
+
+ if((ret = SSL_pending(socket->ssl)) > 0){
+ void *ptr;
+ to_read = ret;
+
+ if((ptr = tsk_realloc(*data, (read + to_read)))){
+ *data = ptr;
+ goto ssl_read;
+ }
+ }
+ }
+
+bail:
+ tsk_safeobj_unlock(socket);
+
+ if(read){
+ *size = read;
+ return 0;
+ }
+ else{
+ return ret;
+ }
+#endif
+}
+
+int tnet_tls_socket_init(tnet_tls_socket_t* socket)
+{
+#if !TNET_HAVE_OPENSSL_H
+ TSK_DEBUG_ERROR("You MUST enable OpenSSL");
+ return -200;
+#else
+ int ret = -1;
+
+ if(!socket){
+ return ret;
+ }
+
+ /* Sets SSL method */
+ socket->ssl_meth = socket->isClient ? TLSv1_client_method() : TLSv1_server_method();
+
+ /* Creates the context */
+ if(!(socket->ssl_ctx = SSL_CTX_new(socket->ssl_meth))){
+ return -3;
+ }
+ else{
+ SSL_CTX_set_mode(socket->ssl_ctx, SSL_MODE_AUTO_RETRY);
+ }
+
+ /*Set cipher list*/
+ if((ret = SSL_CTX_set_cipher_list(socket->ssl_ctx, TNET_CIPHER_LIST)) <= 0){
+ TSK_DEBUG_ERROR("SSL_CTX_set_cipher_list failed [%d]", ret);
+ return -4;
+ }
+
+ /* CLIENT */
+ if(socket->isClient){
+ if(socket->mutual_auth){ /* Mutual authentication */
+ /* Sets Public key (cert) */
+ if((ret = SSL_CTX_use_certificate_file(socket->ssl_ctx, socket->tlsfile_pbk, SSL_FILETYPE_PEM)) <= 0) {
+ TSK_DEBUG_ERROR("SSL_CTX_use_certificate_file failed [%d].", ret);
+ return -3;
+ }
+ /*Sets the password of the private key*/
+ SSL_CTX_set_default_passwd_cb_userdata(socket->ssl_ctx, socket->password);
+
+ /* Sets Private key (cert) */
+ if ((ret = SSL_CTX_use_PrivateKey_file(socket->ssl_ctx, socket->tlsfile_pvk, SSL_FILETYPE_PEM)) <= 0) {
+ TSK_DEBUG_ERROR("SSL_CTX_use_PrivateKey_file failed [%d].", ret);
+ return -4;
+ }
+ /* Checks private key */
+ if(SSL_CTX_check_private_key(socket->ssl_ctx) == 0) {
+ TSK_DEBUG_ERROR("SSL_CTX_check_private_key failed.");
+ return -5;
+ }
+ /* Sets trusted CAs and CA file */
+ if((ret = SSL_CTX_load_verify_locations(socket->ssl_ctx, socket->tlsfile_ca, socket->tlsdir_cas)) < 1) {
+ TSK_DEBUG_ERROR("SSL_CTX_load_verify_locations failed [%s].", ret);
+ return -5;
+ }
+ /* Server verification */
+ SSL_CTX_set_verify(socket->ssl_ctx, SSL_VERIFY_PEER, 0);
+ } /* Mutual authentication */
+ } /* Client */
+
+ /* SSL object. */
+ if(!(socket->ssl = SSL_new(socket->ssl_ctx))){
+ TSK_DEBUG_ERROR("SSL_new(CTX) failed.");
+ return -15;
+ }
+
+ /* Sets FD */
+ if((ret = SSL_set_fd(socket->ssl, socket->fd)) == 0){
+ TSK_DEBUG_ERROR("SSL_set_fd(%u) failed.", socket->fd);
+ return -16;
+ }
+
+ return 0;
+#endif
+}
+
+
+
+
+//=================================================================================================
+// TLS socket object definition
+//
+static tsk_object_t* tnet_tls_socket_ctor(tsk_object_t * self, va_list * app)
+{
+#if TNET_HAVE_OPENSSL_H
+ static tsk_bool_t __ssl_initialized = tsk_false;
+#endif
+ tnet_tls_socket_t *socket = self;
+ if(socket){
+ int ret;
+
+ tsk_safeobj_init(socket);
+
+#if defined(__GNUC__)
+ socket->fd = (tnet_fd_t)va_arg(*app, unsigned);
+#else
+ socket->fd = va_arg(*app, tnet_fd_t);
+#endif
+ socket->tlsfile_ca = tsk_strdup(va_arg(*app, const char *));
+ socket->tlsfile_pvk = tsk_strdup(va_arg(*app, const char *));
+ socket->tlsfile_pbk = tsk_strdup(va_arg(*app, const char *));
+ socket->isClient = va_arg(*app, tsk_bool_t);
+
+ /* Mutual authentication requires that the TLS client-side also hold a certificate. */
+ if(socket->tlsfile_pvk && socket->tlsfile_pbk && socket->tlsfile_ca){
+ socket->mutual_auth = tsk_true;
+ }
+ else{
+ socket->mutual_auth = tsk_false;
+ }
+
+ /* Initialize SSL: http://www.openssl.org/docs/ssl/SSL_library_init.html */
+#if TNET_HAVE_OPENSSL_H
+ if(!__ssl_initialized){
+ __ssl_initialized = tsk_true;
+ SSL_library_init();
+ SSL_load_error_strings();
+ }
+#endif
+ /* Initialize the socket itself: CTX, method, ... */
+ if((ret = tnet_tls_socket_init(socket))){
+ TSK_DEBUG_ERROR("Failed to initialize SSL socket [%d].", ret);
+ }
+ else{
+ socket->initialized = tsk_true;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_tls_socket_dtor(tsk_object_t * self)
+{
+ tnet_tls_socket_t *socket = self;
+ if(socket){
+
+ tsk_safeobj_deinit(socket);
+
+ TSK_FREE(socket->tlsdir_cas);
+ TSK_FREE(socket->tlsfile_ca);
+ TSK_FREE(socket->tlsfile_pvk);
+ TSK_FREE(socket->tlsfile_pbk);
+ TSK_FREE(socket->password);
+
+#if TNET_HAVE_OPENSSL_H
+ if(socket->ssl){
+ //SSL_shutdown(socket->ssl);
+ SSL_free(socket->ssl);
+ }
+ if(socket->ssl_ctx){
+ SSL_CTX_free(socket->ssl_ctx);
+ }
+#endif
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_tls_socket_def_s =
+{
+ sizeof(tnet_tls_socket_t),
+ tnet_tls_socket_ctor,
+ tnet_tls_socket_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_tls_socket_def_t = &tnet_tls_socket_def_s;
+
+
diff --git a/tinyNET/src/tls/tnet_tls.h b/tinyNET/src/tls/tnet_tls.h
new file mode 100644
index 0000000..78305d7
--- /dev/null
+++ b/tinyNET/src/tls/tnet_tls.h
@@ -0,0 +1,57 @@
+/*
+* 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_tls.h
+ * @brief TLS utilitity functions, based on openssl.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TLS_H
+#define TNET_TLS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_types.h"
+
+#include "tsk_object.h"
+
+TNET_BEGIN_DECLS
+
+typedef void tnet_tls_socket_handle_t;
+
+int tnet_tls_socket_isok(const tnet_tls_socket_handle_t* self);
+int tnet_tls_socket_connect(tnet_tls_socket_handle_t* self);
+int tnet_tls_socket_write(tnet_tls_socket_handle_t* self, const void* data, tsk_size_t size);
+#define tnet_tls_socket_send(self, data, size) tnet_tls_socket_write(self, data, size)
+int tnet_tls_socket_recv(tnet_tls_socket_handle_t* self, void** data, tsk_size_t *size, int *isEncrypted);
+
+TINYNET_API tnet_tls_socket_handle_t* tnet_tls_socket_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk, tsk_bool_t isClient);
+TINYNET_API tnet_tls_socket_handle_t* tnet_tls_socket_client_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk);
+TINYNET_API tnet_tls_socket_handle_t* tnet_tls_socket_server_create(tnet_fd_t fd, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_tls_socket_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_TLS_H */
diff --git a/tinyNET/src/tnet.c b/tinyNET/src/tnet.c
new file mode 100644
index 0000000..04f4cba
--- /dev/null
+++ b/tinyNET/src/tnet.c
@@ -0,0 +1,143 @@
+/*
+* 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.c
+ * @brief Network stack.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet.h"
+#include "tnet_utils.h"
+
+#include "tsk_time.h"
+#include "tsk_debug.h"
+
+#include <stdlib.h> /* srand */
+
+/** @mainpage tinyNET API Overview
+*
+* <h1>10 Sockets and Network Functions</h1>
+*
+* All network functions are part of tinyNET projects.<br>
+* You MUST call @ref tnet_startup() before using any network function (tnet_*). tnet_cleanup() is used to terminate use of network functions. <br>
+* The startup function will determine whether the host is a ìlittle-endianî machine or not (at runtime).
+*
+* ======
+*
+* - @ref tnet_socket_group
+* - @ref tnet_utils_group
+* - @ref tnet_dhcp_group
+* - @ref tnet_dhcp6_group
+* - @ref tnet_dns_group
+* - @ref tnet_nat_group (@ref tnet_stun_group, @ref tnet_turn_group, ICE)
+*
+* ======
+*
+*/
+static tsk_bool_t __tnet_started = tsk_false;
+tsk_bool_t tnet_isBigEndian = tsk_false;
+
+/**
+ * @fn tnet_startup
+ * This is probably the most important function. You MUST call this function to initialize the network stack before calling any <b>tnet_*</b> function.
+ * You MUST call @ref tnet_cleanup to cleanup the network stack.
+ *
+ * @sa @ref tnet_cleanup.
+ * @return Zero if succeed and error code otherwise.
+**/
+int tnet_startup()
+{
+ int err = 0;
+ short word = 0x4321;
+
+ if(__tnet_started){
+ goto bail;
+ }
+
+ // rand()
+ srand((unsigned int) tsk_time_epoch());
+
+ // endianness
+ tnet_isBigEndian = ((*(int8_t *)&word) != 0x21);
+#if TNET_UNDER_WINDOWS
+ if(tnet_isBigEndian){
+ TSK_DEBUG_ERROR("Big endian on Windows machine. Is it right?");
+ }
+#endif
+
+#if TNET_UNDER_WINDOWS
+ {
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ wVersionRequested = MAKEWORD(2, 2);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0) {
+ TSK_DEBUG_FATAL("WSAStartup failed with error: %d\n", err);
+ return -1;
+ }
+
+ if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2){
+ TSK_DEBUG_FATAL("Could not find a usable version of Winsock.dll\n");
+ tnet_cleanup();
+ return -2;
+ }
+ else{
+ __tnet_started = tsk_true;
+ TSK_DEBUG_INFO("The Winsock 2.2 dll was found okay\n");
+ }
+ }
+#else
+ __tnet_started = tsk_true;
+#endif /* TNET_UNDER_WINDOWS */
+
+bail:
+ return err;
+}
+
+
+/**
+ * Cleanup the network stack.
+ *
+ * @sa @ref tnet_startup.
+ * @retval Zero if succeed and non-zero error code otherwise.
+**/
+int tnet_cleanup()
+{
+ if(!__tnet_started){
+ goto bail;
+ }
+
+#if TNET_UNDER_WINDOWS
+ __tnet_started = tsk_false;
+ return WSACleanup();
+#else
+ __tnet_started = tsk_false;
+#endif
+
+bail:
+ return 0;
+}
+
diff --git a/tinyNET/src/tnet.h b/tinyNET/src/tnet.h
new file mode 100644
index 0000000..a2b832a
--- /dev/null
+++ b/tinyNET/src/tnet.h
@@ -0,0 +1,45 @@
+/*
+* 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.h
+ * @brief Network stack.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TNET_H
+#define TNET_TNET_H
+
+#include "tinynet_config.h"
+
+#include "tsk_common.h"
+
+TNET_BEGIN_DECLS
+
+TINYNET_API int tnet_startup();
+TINYNET_API int tnet_cleanup();
+
+TNET_END_DECLS
+
+#endif /* TNET_TNET_H */
+
diff --git a/tinyNET/src/tnet_auth.c b/tinyNET/src/tnet_auth.c
new file mode 100644
index 0000000..178aa6f
--- /dev/null
+++ b/tinyNET/src/tnet_auth.c
@@ -0,0 +1,30 @@
+/*
+* 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_auth.c
+ * @brief HTTP Authentication: Basic and Digest Access Authentication as per RFC 2617.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_auth.h"
diff --git a/tinyNET/src/tnet_auth.h b/tinyNET/src/tnet_auth.h
new file mode 100644
index 0000000..05d4059
--- /dev/null
+++ b/tinyNET/src/tnet_auth.h
@@ -0,0 +1,39 @@
+/*
+* 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_auth.h
+ * @brief HTTP Authentication: Basic and Digest Access Authentication as per RFC 2617.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_AUTH_H
+#define TNET_AUTH_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+TNET_END_DECLS
+
+#endif /* TNET_AUTH_H */
diff --git a/tinyNET/src/tnet_endianness.c b/tinyNET/src/tnet_endianness.c
new file mode 100644
index 0000000..afa61c2
--- /dev/null
+++ b/tinyNET/src/tnet_endianness.c
@@ -0,0 +1,98 @@
+/*
+* 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_endianness.c
+ * @brief Byte Ordering.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_endianness.h"
+
+#include "tnet.h"
+
+extern tsk_bool_t tnet_isBigEndian;
+
+/** Converts a 16-bit value from host to TCP/IP network byte order (big-endian).
+* @param x The 16-bit (in host byte order) value to convert.
+* @retval @a x in TCP/IP network byte order.
+*/
+unsigned short tnet_htons(unsigned short x)
+{
+ if(tnet_is_BE()){
+ return x;
+ }
+ else{
+ return ((((uint16_t)(x) & 0xff00) >> 8) |
+ (((uint16_t)(x) & 0x00ff) << 8));
+ }
+}
+
+/* Memory alignment hack */
+unsigned short tnet_htons_2(const void* px)
+{
+ unsigned short y = TSK_TO_UINT16((const uint8_t*)px);
+ return tnet_htons(y);
+}
+
+/** Converts a 32-bit value from host to TCP/IP network byte order (big-endian).
+* @param x The 32-bit (in host byte order) value to convert.
+* @retval @a x in TCP/IP network byte order.
+*/
+unsigned long tnet_htonl(unsigned long x)
+{
+ if(tnet_is_BE()){
+ return x;
+ }
+ else{
+ return ((((uint32_t)(x) & 0xff000000) >> 24) | \
+ (((uint32_t)(x) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(x) & 0x0000ff00) << 8) | \
+ (((uint32_t)(x) & 0x000000ff) << 24));
+ }
+}
+
+/* Memory alignment hack */
+unsigned long tnet_htonl_2(const void* px)
+{
+ unsigned long y = TSK_TO_UINT32((const uint8_t*)px);
+ return tnet_htonl(y);
+}
+
+/** Indicates whether we are on a Big Endian host or not.<br>
+* <b>IMPORTANT</b>: Before calling this function, you should initialize the network stack by using
+* @ref tnet_startup().
+* @retval @a tsk_true if the program is runnin on a Big Endian host and @a tsk_false otherwise.
+*/
+tsk_bool_t tnet_is_BE(){
+ /* If LITTLE_ENDIAN or BIG_ENDIAN macros have been defined in config.h ==> use them
+ * otherwise ==> dyn retrieve the endianness
+ */
+#if LITTLE_ENDIAN
+ return tsk_false;
+#elif BIG_ENDIAN
+ return tsk_true;
+#else
+ return tnet_isBigEndian;
+#endif
+}
diff --git a/tinyNET/src/tnet_endianness.h b/tinyNET/src/tnet_endianness.h
new file mode 100644
index 0000000..cf25729
--- /dev/null
+++ b/tinyNET/src/tnet_endianness.h
@@ -0,0 +1,53 @@
+/*
+* 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_endianness.h
+ * @brief Byte Ordering.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_ENDIANNESS_H
+#define TNET_ENDIANNESS_H
+
+#include "tinynet_config.h"
+
+#include "tsk_common.h" /* tsk_bool_t */
+
+TNET_BEGIN_DECLS
+
+TINYNET_API TNET_INLINE unsigned short tnet_htons(unsigned short x);
+TINYNET_API TNET_INLINE unsigned short tnet_htons_2(const void* px);
+TINYNET_API TNET_INLINE unsigned long tnet_htonl(unsigned long x);
+TINYNET_API TNET_INLINE unsigned long tnet_htonl_2(const void* px);
+TINYNET_API TNET_INLINE tsk_bool_t tnet_is_BE();
+
+#define tnet_ntohs(x) tnet_htons(x)
+#define tnet_ntohs_2(px) tnet_htons_2(px)
+#define tnet_ntohl(x) tnet_htonl(x)
+#define tnet_ntohl_2(px) tnet_htonl_2(px)
+
+TNET_BEGIN_DECLS
+
+#endif /*TNET_ENDIANNESS_H*/
+
diff --git a/tinyNET/src/tnet_hardwares.h b/tinyNET/src/tnet_hardwares.h
new file mode 100644
index 0000000..aa3357b
--- /dev/null
+++ b/tinyNET/src/tnet_hardwares.h
@@ -0,0 +1,64 @@
+/*
+* 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_hardwares.h
+ * @brief List of Hardware types as assigned by the IANA.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#ifndef TNET_HARDWARES_H
+#define TNET_HARDWARES_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+/**
+* List of Hardware types as assigned by the IANA.
+* See RFC 1340, 826 and... for more information.
+*/
+typedef enum tnet_hardware_type_e
+{
+ tnet_htype_Ethernet_10Mb = 1, /**< Ethernet (10Mb) */
+ tnet_htype_Ethernet_3Mb = 2, /**< Experimental Ethernet (3Mb) */
+ tnet_htype_AX_25 = 3, /**< Amateur Radio AX.25 */
+ tnet_htype_Token_Ring = 4, /**< Proteon ProNET Token Ring */
+ tnet_htype_Chaos = 5, /**< Chaos */
+ tnet_htype_IEEE_802_Networks = 6, /**< IEEE 802 Networks */
+ tnet_htype_ARCNET = 7, /**< ARCNET */
+ tnet_htype_Hyperchannel = 8, /**< Hyperchannel */
+ tnet_htype_Lanstar = 9, /**< Lanstar */
+ tnet_htype_Autonet_Short_Address = 10, /**< Autonet Short Address */
+ tnet_htype_ALocalTalk = 11, /**< LocalTalk */
+ tnet_htype_LocalNet= 12, /**< LocalNet (IBM PCNet or SYTEK LocalNET) */
+ tnet_htype_Ultra_link = 13, /**< Ultra link */
+ tnet_htype_SMDS = 14, /**< SMDS */
+ tnet_htype_Frame_Relay = 15, /**< Frame Relay */
+ tnet_htype_ATM = 16, /**< Asynchronous Transmission Mode (ATM) */
+}
+tnet_hardware_type_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_HARDWARES_H */
diff --git a/tinyNET/src/tnet_nat.c b/tinyNET/src/tnet_nat.c
new file mode 100644
index 0000000..cd39b68
--- /dev/null
+++ b/tinyNET/src/tnet_nat.c
@@ -0,0 +1,570 @@
+/*
+* 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_nat.c
+ * @brief NAT Traversal helper functions using STUN, TURN and ICE.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_nat.h"
+
+#include "tnet_endianness.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "tsk_debug.h"
+
+/**@defgroup tnet_nat_group NAT Traversal API (STUN, TURN and ICE).
+*/
+
+
+/**@ingroup tnet_nat_group
+* Creates new NAT context.
+*/
+tnet_nat_context_handle_t* tnet_nat_context_create(tnet_socket_type_t socket_type, const char* username, const char* password)
+{
+ return tsk_object_new(tnet_nat_context_def_t, socket_type, username, password);
+}
+
+/**
+ * Predicate function to find turn allocation by id.
+ *
+ * @param [in,out] item The current list item.
+ * @param [in,out] id A pointer to the allocation identifier.
+ *
+ * @return Zero if current list item hold an allocation with the same id and -1 otherwise.
+**/
+int __pred_find_turn_allocation(const tsk_list_item_t* item, const void* id)
+{
+ if(item)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ if(allocation)
+ {
+ tnet_turn_allocation_id_t alloc_id = *((tnet_turn_allocation_id_t*)id);
+ return (allocation->id == alloc_id) ? 0 : -1;
+ }
+ }
+ return -1;
+}
+
+/** Predicate function to find stun binding by id.
+ *
+ * @param [in,out] item The current list item.
+ * @param [in,out] id A pointer to the binding identifier.
+ *
+ * @return Zero if current list item hold a binding with the same id and -1 otherwise.
+**/
+int __pred_find_stun_binding(const tsk_list_item_t* item, const void* id)
+{
+ if(item)
+ {
+ tnet_stun_binding_t *binding = item->data;
+ if(binding)
+ {
+ tnet_stun_binding_id_t binding_id = *((tnet_stun_binding_id_t*)id);
+ return (binding->id == binding_id) ? 0 : -1;
+ }
+ }
+ return -1;
+}
+
+/** Predicate function to find TURN channel binding by id.
+ *
+ * @param [in,out] item The current list item.
+ * @param [in,out] id A pointer to the TURN channel binding identifier.
+ *
+ * @return Zero if current list item hold a TURN channel binding with the same id and -1 otherwise.
+**/
+int __pred_find_turn_channel_binding(const tsk_list_item_t* item, const void* id)
+{
+ if(item)
+ {
+ tnet_turn_channel_binding_t *binding = item->data;
+ if(binding)
+ {
+ tnet_turn_channel_binding_id_t binding_id = *((tnet_turn_channel_binding_id_t*)id);
+ return (binding->id == binding_id) ? 0 : -1;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Formats binary IP address as string.
+ *
+ * @param in_ip The binary IP address to format (in Host byte order).
+ * @param family The address family.
+ * @param [in,out] out_ip The output string
+ *
+ * @return Zero if current list item hold a binding with the same id and -1 otherwise.
+**/
+int tnet_stun_address_tostring(const uint8_t in_ip[16], tnet_stun_addr_family_t family, char** out_ip)
+{
+ /*if(family == stun_ipv6){
+ tsk_sprintf(out_ip, "%x:%x:%x:%x:%x:%x:%x:%x",
+ tnet_ntohs_2(&in_ip[0]), tnet_ntohs_2(&in_ip[2]), tnet_ntohs_2(&in_ip[4]), tnet_ntohs_2(&in_ip[6]),
+ tnet_ntohs_2(&in_ip[8]), tnet_ntohs_2(&in_ip[10]), tnet_ntohs_2(&in_ip[12]), tnet_ntohs_2(&in_ip[14]));
+ }
+ else if(family == stun_ipv4){
+ tsk_sprintf(out_ip, "%u.%u.%u.%u", (address>>24)&0xFF, (address>>16)&0xFF, (address>>8)&0xFF, (address>>0)&0xFF);
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Unsupported address family: %u.", family);
+ }*/
+ if(family == stun_ipv6){
+ tsk_sprintf(out_ip, "%x:%x:%x:%x:%x:%x:%x:%x",
+ TSK_TO_UINT16(&in_ip[0]), TSK_TO_UINT16(&in_ip[2]), TSK_TO_UINT16(&in_ip[4]), TSK_TO_UINT16(&in_ip[6]),
+ TSK_TO_UINT16(&in_ip[8]), TSK_TO_UINT16(&in_ip[10]), TSK_TO_UINT16(&in_ip[12]), TSK_TO_UINT16(&in_ip[14]));
+ }
+ else if(family == stun_ipv4){
+ tsk_sprintf(out_ip, "%u.%u.%u.%u", in_ip[0], in_ip[1], in_ip[2], in_ip[3]);
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Unsupported address family: %u.", family);
+ }
+
+ return -1;
+}
+
+
+/**@ingroup tnet_nat_group
+ *
+ * Sets the address of the STUN/TURN server.
+ *
+ * @param [in,out] self The NAT context.
+ * @param [in,out] server_address The address of server.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_set_server_address(tnet_nat_context_handle_t* self, const char* server_address)
+{
+ tnet_nat_context_t* context = self;
+
+ if(context){
+ tsk_strupdate(&(context->server_address), server_address);
+ return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Sets the address and port of the STUN/TURN server.
+ *
+ * @param [in,out] self The NAT context.
+ * @param [in,out] server_address The address of server.
+ * @param server_port The server port.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_set_server(tnet_nat_context_handle_t* self, const char* server_address, tnet_port_t server_port)
+{
+ tnet_nat_context_t* context = self;
+
+ if(context){
+ tsk_strupdate(&(context->server_address), server_address);
+ context->server_port = server_port;
+
+ return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Creates and sends a STUN2 binding request to the STUN/TURN server in order to get the server reflexive
+ * address associated to this file descriptor (or socket). The caller should call @ref tnet_nat_stun_unbind to destroy the binding.
+ *
+ * @param [in,out] self The NAT context.
+ * @param localFD The local file descriptor (or socket) for which to get the reflexive server address.
+ *
+ * @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.
+ *
+ * @sa @ref tnet_nat_stun_unbind.
+**/
+tnet_stun_binding_id_t tnet_nat_stun_bind(const tnet_nat_context_handle_t* self, const tnet_fd_t localFD)
+{
+ const tnet_nat_context_t* context = self;
+ if(context){
+ return tnet_stun_bind(context, localFD);
+ }
+ return TNET_STUN_INVALID_BINDING_ID;
+}
+
+/**@ingroup tnet_nat_group
+ * Gets the server reflexive address associated to this STUN2 binding.
+ *
+ *
+ * @param [in,out] self The NAT context.
+ * @param id The id of the STUN2 binding conetxt (obtained using @ref tnet_nat_stun_bind) holding the server-reflexive address.
+ * @param [in,out] ipaddress The reflexive IP address. It is up the the caller to free the returned string
+ * @param [in,out] port The reflexive port.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_stun_get_reflexive_address(const tnet_nat_context_handle_t* self, tnet_stun_binding_id_t id, char** ipaddress, tnet_port_t *port)
+{
+ const tnet_nat_context_t* context = self;
+ if(context){
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->stun_bindings, __pred_find_stun_binding, &id);
+ if(item && item->data){
+ tnet_stun_binding_t *binding = item->data;
+ /*STUN2: XOR-MAPPED-ADDRESS */
+ if(binding->xmaddr){
+ int ret = 0;
+ if(ipaddress){
+ ret = tnet_stun_address_tostring(binding->xmaddr->xaddress, binding->xmaddr->family, ipaddress);
+ }
+ if(port){
+ *port = /*tnet_ntohs*/(binding->xmaddr->xport);
+ }
+ return ret;
+ }
+
+ /*STUN1: MAPPED-ADDRESS*/
+ if(binding->maddr){
+ int ret = 0;
+ if(ipaddress){
+ ret = tnet_stun_address_tostring(binding->maddr->address, binding->maddr->family, ipaddress);
+ }
+ if(port){
+ *port = /*tnet_ntohs*/(binding->maddr->port);
+ }
+ return ret;
+ }
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Removes a STUN2 binding from the NAT context.
+ *
+ * @param [in,out] self The NAT context from which to remove the STUN2 binding.
+ * @param id The id of the STUN2 binding to remove.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+ *
+ *
+ * @sa @ref tnet_nat_stun_bind.
+**/
+int tnet_nat_stun_unbind(const tnet_nat_context_handle_t* self, tnet_stun_binding_id_t id)
+{
+ const tnet_nat_context_t* context = self;
+ if(context)
+ {
+ tsk_list_remove_item_by_pred(context->stun_bindings, __pred_find_stun_binding, &id);
+ return 0;
+ }
+ return -1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/**@ingroup tnet_nat_group
+ *
+ * Creates TURN allocation as per draft-ietf-behave-turn-16 subclause 6. This function will also
+ * send an allocation request to the server (subclause 6.1).
+ *
+ * @param [in,out] self The NAT context.
+ * @param localFD The local file descriptor.
+ *
+ * @return A valid TURN allocation id if succeed and @ref TNET_TURN_INVALID_ALLOCATION_ID otherwise.
+ *
+ * @sa @ref tnet_nat_turn_unallocate.
+**/
+tnet_turn_allocation_id_t tnet_nat_turn_allocate(const tnet_nat_context_handle_t* self, const tnet_fd_t localFD)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(self)
+ {
+ return tnet_turn_allocate(self, localFD, context->socket_type);
+ }
+
+ return TNET_TURN_INVALID_ALLOCATION_ID;
+}
+
+/**@ingroup tnet_nat_group
+ * Gets the STUN server-refelexive IP address and port associated to this TURN allocation.
+ *
+ * @param [in,out] self The NAT context.
+ * @param id The id of the TURN allocation for which to to get server-reflexive IP address and port.
+ * @param [in,out] ipaddress The server-reflexive IP address.
+ * @param [in,out] port The server-reflexive port.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_turn_get_reflexive_address(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, char** ipaddress, tnet_port_t *port)
+{
+ const tnet_nat_context_t* context = self;
+ if(context)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->allocations, __pred_find_turn_allocation, &id);
+ if(item && item->data)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ /*STUN2: XOR-MAPPED-ADDRESS */
+ if(allocation->xmaddr)
+ {
+ int ret = tnet_stun_address_tostring(allocation->xmaddr->xaddress, allocation->xmaddr->family, ipaddress);
+ *port = /*tnet_ntohs*/(allocation->xmaddr->xport);
+ return ret;
+ }
+
+ /*STUN1: MAPPED-ADDRESS*/
+ if(allocation->maddr)
+ {
+ int ret = tnet_stun_address_tostring(allocation->maddr->address, allocation->maddr->family, ipaddress);
+ *port = /*tnet_ntohs*/(allocation->maddr->port);
+ return ret;
+ }
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Refresh a TURN allocation previously created using @ref tnet_nat_turn_allocate.
+ *
+ * @param [in,out] self The NAT context.
+ * @param id The id of the TURN allocation to refresh.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+**/
+int tnet_nat_turn_allocation_refresh(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(context)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->allocations, __pred_find_turn_allocation, &id);
+ if(item && item->data)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ return tnet_turn_allocation_refresh(self, allocation);
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ *
+ * Unallocate/remove a TURN allocation from the server.
+ *
+ * @param [in,out] self The NAT context from which to remove the allocation.
+ * @param id The id of the TURN allocation to remove.
+ *
+ * @return Zero if succeed and non zero error code otherwise.
+ *
+ * @sa @ref tnet_nat_turn_allocate.
+**/
+int tnet_nat_turn_unallocate(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(context)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->allocations, __pred_find_turn_allocation, &id);
+ if(item && item->data)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ return tnet_turn_unallocate(self, allocation);
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+ * Creates TURN channel binding as per draft-ietf-behave-turn-16 sublause 11 and send it to the
+ * server as per subclause 11.1.
+ *
+ *
+ * @param [in,out] self The NAT context.
+ * @param id The id of the TURN allocation associated to this binding.
+ * @param [in,out] peer The XOR remote peer for the channel binding.
+ *
+ * @return A valid TURN channel binding id if succeed and @ref TNET_TURN_INVALID_CHANNEL_BINDING_ID otherwise.
+**/
+tnet_turn_channel_binding_id_t tnet_nat_turn_channel_bind(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, struct sockaddr_storage *peer)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(context)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->allocations, __pred_find_turn_allocation, &id);
+ if(item && item->data)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ return tnet_turn_channel_bind(self, allocation, peer);
+ }
+ }
+ return TNET_TURN_INVALID_CHANNEL_BINDING_ID;
+}
+
+/**@ingroup tnet_nat_group
+*/
+int tnet_nat_turn_channel_refresh(const tnet_nat_context_handle_t* self, tnet_turn_channel_binding_id_t id)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(context)
+ {
+ tsk_list_item_t* curr;
+ tsk_list_foreach(curr, context->allocations)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(((tnet_turn_allocation_t *)curr->data)->channel_bindings, __pred_find_turn_channel_binding, &id);
+ if(item && item->data)
+ {
+ return tnet_turn_channel_refresh(context, (tnet_turn_channel_binding_t *)item->data);
+ }
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+*/
+int tnet_nat_turn_channel_send(const tnet_nat_context_handle_t* self, tnet_turn_channel_binding_id_t id, const void* data, tsk_size_t size, int indication)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(context && data && size)
+ {
+ tsk_list_item_t* curr;
+ tsk_list_foreach(curr, context->allocations)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(((tnet_turn_allocation_t *)curr->data)->channel_bindings, __pred_find_turn_channel_binding, &id);
+ if(item && item->data)
+ {
+ return tnet_turn_channel_senddata(context, (tnet_turn_channel_binding_t *)item->data, data, size, indication);
+ }
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_nat_group
+*/
+int tnet_nat_turn_add_permission(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, const char* ipaddress, uint32_t timeout)
+{
+ const tnet_nat_context_t* context = self;
+
+ if(self)
+ {
+ const tsk_list_item_t* item = tsk_list_find_item_by_pred(context->allocations, __pred_find_turn_allocation, &id);
+ if(item && item->data)
+ {
+ tnet_turn_allocation_t *allocation = item->data;
+ return tnet_turn_add_permission(self, allocation, ipaddress, timeout);
+ }
+ }
+ return -1;
+}
+
+
+//=================================================================================================
+// NAT CONTEXT object definition
+//
+static tsk_object_t* tnet_nat_context_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_nat_context_t *context = self;
+ if(context){
+ context->socket_type = va_arg(*app, tnet_socket_type_t);
+
+ context->username = tsk_strdup(va_arg(*app, const char*));
+ context->password = tsk_strdup(va_arg(*app, const char*));
+
+ context->server_port = TNET_NAT_TCP_UDP_DEFAULT_PORT;
+
+ /* 7.2.1. Sending over UDP
+ In fixed-line access links, a value of 500 ms is RECOMMENDED.
+ */
+ context->RTO = TNET_NAT_DEFAULT_RTO;
+
+ /* 7.2.1. Sending over UDP
+ Rc SHOULD be configurable and SHOULD have a default of 7.
+ */
+ context->Rc = TNET_NAT_DEFAULT_RC;
+
+ context->software = tsk_strdup(TNET_SOFTWARE);
+ //context->enable_evenport = 1;
+ //context->enable_fingerprint = 1;
+ context->enable_integrity = 0;
+ context->enable_dontfrag = 0;//TNET_SOCKET_TYPE_IS_DGRAM(context->socket_type) ? 1 : 0;
+
+ context->allocations = tsk_list_create();
+ context->stun_bindings = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_nat_context_dtor(tsk_object_t * self)
+{
+ tnet_nat_context_t *context = self;
+ if(context){
+ TSK_FREE(context->username);
+ TSK_FREE(context->password);
+ TSK_FREE(context->software);
+ TSK_FREE(context->server_address);
+
+ TSK_OBJECT_SAFE_FREE(context->allocations);
+ TSK_OBJECT_SAFE_FREE(context->stun_bindings);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_nat_context_def_s =
+{
+ sizeof(tnet_nat_context_t),
+ tnet_nat_context_ctor,
+ tnet_nat_context_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_nat_context_def_t = &tnet_nat_context_def_s;
diff --git a/tinyNET/src/tnet_nat.h b/tinyNET/src/tnet_nat.h
new file mode 100644
index 0000000..023f2d5
--- /dev/null
+++ b/tinyNET/src/tnet_nat.h
@@ -0,0 +1,120 @@
+/*
+* 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_nat.h
+ * @brief NAT Traversal helper functions using STUN, TURN and ICE.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_NAT_H
+#define TNET_NAT_H
+
+#include "tinynet_config.h"
+
+#include "stun/tnet_stun.h"
+#include "turn/tnet_turn.h"
+
+#include "tnet_proto.h"
+#include "tnet_types.h"
+
+#include "tsk_object.h"
+
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_nat_group
+* Estimate of the round-trip time (RTT) in millisecond.
+*/
+#define TNET_NAT_DEFAULT_RTO 500
+/**@ingroup tnet_nat_group
+* 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 TNET_NAT_DEFAULT_RC /*7*/3/* 7 is too hight */
+/**@ingroup tnet_nat_group
+*/
+#define TNET_NAT_TCP_UDP_DEFAULT_PORT 3478
+
+/**@ingroup tnet_nat_group
+ * NAT context.
+**/
+typedef struct tnet_nat_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ //tnet_fd_t localFD; /**< Local file descriptor. */
+ tnet_socket_type_t socket_type;
+
+ char* username; /**< The username to use to authenticate against the TURN/STUN server. */
+ char* password; /**< The password to use to authenticate against the TURN/STUN server. */
+ char* software; /**< The turn/stun client name. */
+
+ char* server_address; /**< TURN/STUN server address (could be FQDN or IP) */
+ tnet_port_t server_port; /**< TURN/STUN server port. */
+
+ uint16_t RTO; /**< Estimate of the round-trip time (RTT) in millisecond. */
+ uint16_t Rc; /**< Number of retransmissions for UDP in millisecond. */
+
+ unsigned enable_dontfrag:1;
+ unsigned enable_integrity:1;
+ unsigned enable_evenport:1;
+ unsigned enable_fingerprint:1; /**< Indicates whether to add the 'fingerprint' attribute in all outgoing stun/turn requests. */
+ unsigned use_dnsquery:1; /**< Indicates whether to use DNS SRV query to find the stun/turn ip address. */
+
+ tnet_turn_allocations_L_t *allocations; /**< List of all allocations associated to this context. */
+ tnet_stun_bindings_L_t *stun_bindings; /**< List of all STUN2 bindings associated to this context. */
+}
+tnet_nat_context_t;
+
+/**@ingroup tnet_nat_group
+ * Handle to the NAT context(@ref tnet_nat_context_t).
+**/
+typedef void tnet_nat_context_handle_t;
+
+TINYNET_API int tnet_nat_set_server_address(tnet_nat_context_handle_t* self, const char* server_address);
+TINYNET_API int tnet_nat_set_server(tnet_nat_context_handle_t* self, const char* server_address, tnet_port_t server_port);
+
+TINYNET_API tnet_stun_binding_id_t tnet_nat_stun_bind(const tnet_nat_context_handle_t* self, const tnet_fd_t localFD);
+TINYNET_API int tnet_nat_stun_get_reflexive_address(const tnet_nat_context_handle_t* self, tnet_stun_binding_id_t id, char** ipaddress, tnet_port_t *port);
+TINYNET_API int tnet_nat_stun_unbind(const tnet_nat_context_handle_t* self, tnet_stun_binding_id_t id);
+
+TINYNET_API tnet_turn_allocation_id_t tnet_nat_turn_allocate(const tnet_nat_context_handle_t* self, const tnet_fd_t localFD);
+TINYNET_API int tnet_nat_turn_get_reflexive_address(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, char** ipaddress, tnet_port_t *port);
+TINYNET_API int tnet_nat_turn_allocation_refresh(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id);
+TINYNET_API int tnet_nat_turn_unallocate(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id);
+TINYNET_API tnet_turn_channel_binding_id_t tnet_nat_turn_channel_bind(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, struct sockaddr_storage *peer);
+TINYNET_API int tnet_nat_turn_channel_refresh(const tnet_nat_context_handle_t* self, tnet_turn_channel_binding_id_t id);
+TINYNET_API int tnet_nat_turn_channel_send(const tnet_nat_context_handle_t* self, tnet_turn_channel_binding_id_t id, const void* data, tsk_size_t size, int indication);
+#define tnet_nat_turn_channel_sendindication(context, channel_id, data, size) tnet_nat_turn_channel_send(context, channel_id, data, size, 1)
+#define tnet_nat_turn_channel_senddata(context, channel_id, data, size) tnet_nat_turn_channel_send(context, channel_id, data, size, 0)
+TINYNET_API int tnet_nat_turn_add_permission(const tnet_nat_context_handle_t* self, tnet_turn_allocation_id_t id, const char* ipaddress, uint32_t timeout);
+
+TINYNET_API tnet_nat_context_handle_t* tnet_nat_context_create(tnet_socket_type_t socket_type, const char* username, const char* password);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_nat_context_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_NAT_H */
diff --git a/tinyNET/src/tnet_poll.c b/tinyNET/src/tnet_poll.c
new file mode 100644
index 0000000..68a6589
--- /dev/null
+++ b/tinyNET/src/tnet_poll.c
@@ -0,0 +1,109 @@
+/*
+* 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.
+*
+*/
+#include "tnet_poll.h"
+
+#if TNET_USE_POLL && !TNET_HAVE_POLL
+
+/**
+ *
+ * @brief poll() method implementation for multiplexing network sockets.
+ *
+ * @param fds An array of pollfd structures.
+ * @param nfds The number of file descriptors set in fds[ ].
+ * @param timeout How long poll() should wait for an event to occur (in milliseconds).
+ *
+ * @return The number of elements in fdarray for which an revents member of the POLLFD structure is nonzero.
+ * If the the returned value if <0 this mean that error occurred.
+**/
+
+int tnet_poll(tnet_pollfd_t fds[ ], tnet_nfds_t nfds, int timeout)
+{
+ tsk_size_t i;
+ int ret;
+ int highest_fd = -1;
+
+ fd_set readfds;
+ fd_set writefds;
+ fd_set exceptfds;
+ struct timeval timetowait;
+
+ /*
+ * cleanup fd_sets
+ */
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&exceptfds);
+
+ /*
+ * set timeout
+ */
+ if(timeout >=0){
+ timetowait.tv_sec = (timeout/1000);
+ timetowait.tv_usec = (timeout%1000) * 1000;
+ }
+
+ /*
+ * add descriptors to the fd_sets
+ */
+ for(i = 0; i<nfds; i++){
+ if(fds[i].fd != TNET_INVALID_FD){
+ if(fds[i].events & TNET_POLLIN){
+ FD_SET(fds[i].fd, &readfds);
+ }
+ if(fds[i].events & TNET_POLLOUT){
+ FD_SET(fds[i].fd, &writefds);
+ }
+ if(fds[i].events & TNET_POLLPRI){
+ FD_SET(fds[i].fd, &exceptfds);
+ }
+ }
+
+ highest_fd = (highest_fd < fds[i].fd) ? fds[i].fd : highest_fd;
+ }
+
+ /*======================================
+ * select
+ */
+ if((ret = select(highest_fd + 1, &readfds, &writefds, &exceptfds, (timeout >=0) ? &timetowait : 0)) >= 0){
+ for(i = 0; i<nfds; i++){
+ if(fds[i].fd != TNET_INVALID_FD){
+ fds[i].revents = 0;
+
+ if(FD_ISSET(fds[i].fd, &readfds)){
+ fds[i].revents |= TNET_POLLIN;
+ }
+ if(FD_ISSET(fds[i].fd, &writefds)){
+ fds[i].revents |= TNET_POLLOUT;
+ }
+ if(FD_ISSET(fds[i].fd, &exceptfds)){
+ fds[i].revents |= TNET_POLLPRI;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+#endif /* TNET_USE_POLL */
+
+
diff --git a/tinyNET/src/tnet_poll.h b/tinyNET/src/tnet_poll.h
new file mode 100644
index 0000000..a8845e0
--- /dev/null
+++ b/tinyNET/src/tnet_poll.h
@@ -0,0 +1,92 @@
+/*
+* 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_poll.h
+ * @brief poll() method implementation for multiplexing network sockets.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_POLL_H
+#define TNET_POLL_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+#if TNET_USE_POLL
+
+#include "tnet_types.h"
+
+typedef unsigned long tnet_nfds_t;
+
+#if TNET_HAVE_POLL
+
+typedef struct pollfd tnet_pollfd_t;
+
+#define TNET_POLLRDNORM POLLRDNORM
+#define TNET_POLLRDBAND POLLRDBAND
+#define TNET_POLLIN POLLIN
+#define TNET_POLLPRI POLLPRI
+
+#define TNET_POLLWRNORM POLLWRNORM
+#define TNET_POLLOUT POLLOUT
+#define TNET_POLLWRBAND POLLWRBAND
+
+#define TNET_POLLERR POLLERR
+#define TNET_POLLHUP POLLHUP
+#define TNET_POLLNVAL POLLNVAL
+
+#if TNET_UNDER_WINDOWS
+# define tnet_poll WSAPoll
+#else
+# define tnet_poll poll
+#endif /* TNET_UNDER_WINDOWS */
+
+#else
+
+typedef struct tnet_pollfd_s
+{
+ tnet_fd_t fd;
+ short events;
+ short revents;
+}
+tnet_pollfd_t;
+
+#define TNET_POLLIN 0x0001 /* There is data to read */
+#define TNET_POLLPRI 0x0002 /* There is urgent data to read */
+#define TNET_POLLOUT 0x0004 /* Writing now will not block */
+#define TNET_POLLERR 0x0008 /* Error condition */
+#define TNET_POLLHUP 0x0010 /* Hung up */
+#define TNET_POLLNVAL 0x0020 /* Invalid request: fd not open */
+
+int tnet_poll(tnet_pollfd_t fds[ ], tnet_nfds_t nfds, int timeout);
+
+#endif /* TNET_HAVE_POLL */
+
+#endif /* TNET_USE_POLL */
+
+TNET_END_DECLS
+
+#endif /* TNET_POLL_H */
+
diff --git a/tinyNET/src/tnet_proto.h b/tinyNET/src/tnet_proto.h
new file mode 100644
index 0000000..f1fefbe
--- /dev/null
+++ b/tinyNET/src/tnet_proto.h
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_proto.h
+ * @brief List of all assigned protocols as defined by the IANA (http://www.iana.org/assignments/protocol-numbers/).
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_PROTO_H
+#define TNET_PROTO_H
+
+#include "tinynet_config.h"
+
+TNET_BEGIN_DECLS
+
+/**
+ * @enum tnet_proto_e
+ *
+ * @brief List of all assigned protocols as defined by the IANA
+ (http://www.iana.org/assignments/protocol-numbers/).
+**/
+typedef enum tnet_proto_e
+{
+ TNET_PROTO_HOPOPT = 0, /**< HOPOPT IPv6 Hop-by-Hop Option [RFC1883] */
+ TNET_PROTO_ICMP = 1, /**< ICMP Internet Control Message [RFC792] */
+ TNET_PROTO_IGMP = 2, /**< IGMP Internet Group Management [RFC1112] */
+ TNET_PROTO_GGP = 3, /**< GGP Gateway-to-Gateway [RFC823] */
+ TNET_PROTO_IP = 4, /**< IP IP in IP (encapsulation) [RFC2003] */
+ TNET_PROTO_ST = 5, /**< ST Stream [RFC1190][RFC1819] */
+ TNET_PROTO_TCP = 6, /**< TCP Transmission Control [RFC793] */
+ TNET_PROTO_CBT = 7, /**< CBT CBT [Ballardie] */
+ TNET_PROTO_EGP = 8, /**< EGP Exterior Gateway Protocol [RFC888][DLM1] */
+ TNET_PROTO_IGP = 9, /**< IGP any private interior gateway [IANA](used by Cisco for their IGRP) */
+ TNET_PROTO_BBN_RCC_MON = 10, /**< BBN-RCC-MON BBN RCC Monitoring [SGC] */
+ TNET_PROTO_NVP_II = 11, /**< NVP-II Network Voice Protocol [RFC741][SC3] */
+ TNET_PROTO_PUP = 12, /**< PUP PUP [PUP][XEROX] */
+ TNET_PROTO_ARGUS = 13, /**< ARGUS ARGUS [RWS4] */
+ TNET_PROTO_EMCON = 14, /**< EMCON EMCON [BN7] */
+ TNET_PROTO_XNET = 15, /**< XNET Cross Net Debugger [IEN158][JFH2] */
+ TNET_PROTO_CHAOS = 16, /**< CHAOS Chaos [NC3] */
+ TNET_PROTO_UDP = 17, /**< UDP User Datagram [RFC768][JBP] */
+ TNET_PROTO_MUX = 18, /**< MUX Multiplexing [IEN90][JBP] */
+ TNET_PROTO_DCN_MEAS = 19, /**< DCN-MEAS DCN Measurement Subsystems [DLM1] */
+ TNET_PROTO_HMP = 20, /**< HMP Host Monitoring [RFC869][RH6] */
+ TNET_PROTO_PRM = 21, /**< PRM Packet Radio Measurement [ZSU] */
+ TNET_PROTO_XNS_IDP = 22, /**< XNS-IDP XEROX NS IDP [ETHERNET][XEROX] */
+ TNET_PROTO_TRUNK_1 = 23, /**< TRUNK-1 Trunk-1 [BWB6] */
+ TNET_PROTO_TRUNK_2 = 24, /**< TRUNK-2 Trunk-2 [BWB6] */
+ TNET_PROTO_LEAF_1 = 25, /**< LEAF-1 Leaf-1 [BWB6] */
+ TNET_PROTO_LEAF_2 = 26, /**< LEAF-2 Leaf-2 [BWB6] */
+ TNET_PROTO_RDP = 27, /**< RDP Reliable Data Protocol [RFC908][RH6] */
+ TNET_PROTO_IRTP = 28, /**< IRTP Internet Reliable Transaction [RFC938][TXM] */
+ TNET_PROTO_ISO_TP4 = 29, /**< ISO-TP4 ISO Transport Protocol Class 4 [RFC905][RC77] */
+ TNET_PROTO_NETBLT = 30, /**< NETBLT Bulk Data Transfer Protocol [RFC969][DDC1] */
+ TNET_PROTO_MFE_NSP = 31, /**< MFE-NSP MFE Network Services Protocol [MFENET][BCH2] */
+ TNET_PROTO_MERIT_INP = 32, /**< MERIT-INP MERIT Internodal Protocol [HWB] */
+ TNET_PROTO_DCCP = 33, /**< DCCP Datagram Congestion Control Protocol [RFC4340] */
+ TNET_PROTO_3PC = 34, /**< 3PC Third Party Connect Protocol [SAF3] */
+ TNET_PROTO_IDPR = 35, /**< IDPR Inter-Domain Policy Routing Protocol [MXS1] */
+ TNET_PROTO_XTP = 36, /**< XTP XTP [GXC] */
+ TNET_PROTO_DDP = 37, /**< DDP Datagram Delivery Protocol [WXC] */
+ TNET_PROTO_IDPR_CMTP = 38, /**< IDPR-CMTP IDPR Control Message Transport Proto [MXS1] */
+ TNET_PROTO_TP_PP = 39, /**< TP++ TP++ Transport Protocol [DXF] */
+ TNET_PROTO_IL = 40, /**< IL IL Transport Protocol [Presotto] */
+ TNET_PROTO_IPv6 = 41, /**< IPv6 Ipv6 [Deering] */
+ TNET_PROTO_SDRP = 42, /**< SDRP Source Demand Routing Protocol [DXE1] */
+ TNET_PROTO_IPv6_Route = 43, /**< IPv6-Route Routing Header for IPv6 [Deering] */
+ TNET_PROTO_IPv6_Frag = 44, /**< IPv6-Frag Fragment Header for IPv6 [Deering] */
+ TNET_PROTO_IDRP = 45, /**< IDRP Inter-Domain Routing Protocol [Hares] */
+ TNET_PROTO_RSVP = 46, /**< RSVP Reservation Protocol [Braden] */
+ TNET_PROTO_GRE = 47, /**< GRE General Routing Encapsulation [Li] */
+ TNET_PROTO_DSR = 48, /**< DSR Dynamic Source Routing Protocol [RFC4728] */
+ TNET_PROTO_BNA = 49, /**< BNA BNA [Salamon] */
+ TNET_PROTO_ESP = 50, /**< ESP Encap Security Payload [RFC4303] */
+ TNET_PROTO_AH = 51, /**< AH Authentication Header [RFC4302] */
+ TNET_PROTO_I_NLSP = 52, /**< I-NLSP Integrated Net Layer Security TUBA [GLENN] */
+ TNET_PROTO_SWIPE = 53, /**< SWIPE IP with Encryption [JI6] */
+ TNET_PROTO_NARP = 54, /**< NARP NBMA Address Resolution Protocol [RFC1735] */
+ TNET_PROTO_MOBILE = 55, /**< MOBILE IP Mobility [Perkins] */
+ TNET_PROTO_TLSP = 56, /**< TLSP Transport Layer Security Protocol [Oberg] using Kryptonet key management */
+ TNET_PROTO_SKIP = 57, /**< SKIP SKIP [Markson] */
+ TNET_PROTO_IPv6_ICMP = 58, /**< IPv6-ICMP ICMP for IPv6 [RFC1883] */
+ TNET_PROTO_IPv6_NoNxt = 59, /**< IPv6-NoNxt No Next Header for IPv6 [RFC1883] */
+ TNET_PROTO_IPv6_Opts = 60, /**< IPv6-Opts Destination Options for IPv6 [RFC1883] */
+ TNET_PROTO_ANY_INTERNAL = 61, /**< any host internal protocol [IANA] */
+ TNET_PROTO_CFTP = 62, /**< CFTP CFTP [CFTP][HCF2] */
+ TNET_PROTO_ANY_LOCAL = 63, /**< any local network [IANA] */
+ TNET_PROTO_SAT_EXPAK = 64, /**< SAT-EXPAK SATNET and Backroom EXPAK [SHB] */
+ TNET_PROTO_KRYPTOLAN = 65, /**< KRYPTOLAN Kryptolan [PXL1] */
+ TNET_PROTO_RVD = 66, /**< RVD MIT Remote Virtual Disk Protocol [MBG] */
+ TNET_PROTO_IPPC = 67, /**< IPPC Internet Pluribus Packet Core [SHB] */
+ TNET_PROTO_ANY_DISTRIBUTED = 68, /**< any distributed file system [IANA] */
+ TNET_PROTO_SAT_MON = 69, /**< SAT-MON SATNET Monitoring [SHB] */
+ TNET_PROTO_VISA = 70, /**< VISA VISA Protocol [GXT1] */
+ TNET_PROTO_IPCV = 71, /**< IPCV Internet Packet Core Utility [SHB] */
+ TNET_PROTO_CPNX = 72, /**< CPNX Computer Protocol Network Executive [DXM2] */
+ TNET_PROTO_CPHB = 73, /**< CPHB Computer Protocol Heart Beat [DXM2] */
+ TNET_PROTO_WSN = 74, /**< WSN Wang Span Network [VXD] */
+ TNET_PROTO_PVP = 75, /**< PVP Packet Video Protocol [SC3] */
+ TNET_PROTO_BR_SAT_MON = 76, /**< BR-SAT-MON Backroom SATNET Monitoring [SHB] */
+ TNET_PROTO_SUN_ND = 77, /**< SUN-ND SUN ND PROTOCOL-Temporary [WM3] */
+ TNET_PROTO_WB_MON = 78, /**< WB-MON WIDEBAND Monitoring [SHB] */
+ TNET_PROTO_WB_EXPAK = 79, /**< WB-EXPAK WIDEBAND EXPAK [SHB] */
+ TNET_PROTO_ISO_IP = 80, /**< ISO-IP ISO Internet Protocol [MTR] */
+ TNET_PROTO_VMTP = 81, /**< VMTP VMTP [DRC3] */
+ TNET_PROTO_SECURE_VMTP = 82, /**< SECURE-VMTP SECURE-VMTP [DRC3] */
+ TNET_PROTO_VINES = 83, /**< VINES VINES [BXH] */
+ TNET_PROTO_TTP = 84, /**< TTP TTP [JXS] */
+ TNET_PROTO_NSFNET_IGP = 85, /**< NSFNET-IGP NSFNET-IGP [HWB] */
+ TNET_PROTO_DGP = 86, /**< DGP Dissimilar Gateway Protocol [DGP][ML109] */
+ TNET_PROTO_TCF = 87, /**< TCF TCF [GAL5] */
+ TNET_PROTO_EIGRP = 88, /**< EIGRP EIGRP [CISCO][GXS] */
+ TNET_PROTO_OSPFIGP = 89, /**< OSPFIGP OSPFIGP [RFC1583][JTM4] */
+ TNET_PROTO_Sprite_RPC = 90, /**< Sprite-RPC Sprite RPC Protocol [SPRITE][BXW] */
+ TNET_PROTO_LARP = 91, /**< LARP Locus Address Resolution Protocol [BXH] */
+ TNET_PROTO_MTP = 92, /**< MTP Multicast Transport Protocol [SXA] */
+ TNET_PROTO_AX25 = 93, /**< AX.25 AX.25 Frames [BK29] */
+ TNET_PROTO_IPIP = 94, /**< IPIP IP-within-IP Encapsulation Protocol [JI6] */
+ TNET_PROTO_MICP = 95, /**< MICP Mobile Internetworking Control Pro. [JI6] */
+ TNET_PROTO_SCC_SP = 96, /**< SCC-SP Semaphore Communications Sec. Pro. [HXH] */
+ TNET_PROTO_ETHERIP = 97, /**< ETHERIP Ethernet-within-IP Encapsulation [RFC3378] */
+ TNET_PROTO_ENCAP = 98, /**< ENCAP Encapsulation Header [RFC1241,RXB3] */
+ TNET_PROTO_ANY_PRIV_ENC = 99, /**< any private encryption scheme [IANA] */
+ TNET_PROTO_GMTP = 100, /**< GMTP GMTP [RXB5] */
+ TNET_PROTO_IFMP = 101, /**< IFMP Ipsilon Flow Management Protocol [Hinden] */
+ TNET_PROTO_PNNI = 102, /**< PNNI PNNI over IP [Callon] */
+ TNET_PROTO_PIM = 103, /**< PIM Protocol Independent Multicast [Farinacci] */
+ TNET_PROTO_ARIS = 104, /**< ARIS ARIS [Feldman] */
+ TNET_PROTO_SCPS = 105, /**< SCPS SCPS [Durst] */
+ TNET_PROTO_QNX = 106, /**< QNX QNX [Hunter] */
+ TNET_PROTO_AN = 107, /**< A/N Active Networks [Braden] */
+ TNET_PROTO_IPComp = 108, /**< IPComp IP Payload Compression Protocol [RFC2393] */
+ TNET_PROTO_SNP = 109, /**< SNP Sitara Networks Protocol [Sridhar] */
+ TNET_PROTO_Compaq_Peer = 110, /**< Compaq-Peer Compaq Peer Protocol [Volpe] */
+ TNET_PROTO_IPX_in_IP = 11, /**< IPX-in-IP IPX in IP [Lee] */
+ TNET_PROTO_VRRP = 112, /**< VRRP Virtual Router Redundancy Protocol [RFC3768][RFC-ietf-vrrp-unified-spec-05.txt] */
+ TNET_PROTO_PGM = 113, /**< PGM PGM Reliable Transport Protocol [Speakman] */
+ TNET_PROTO_ANY_ZERO_HOP = 114, /**< any 0-hop protocol [IANA] */
+ TNET_PROTO_L2TP = 115, /**< L2TP Layer Two Tunneling Protocol [Aboba] */
+ TNET_PROTO_DDX = 116, /**< DDX D-II Data Exchange (DDX) [Worley] */
+ TNET_PROTO_IATP = 117, /**< IATP Interactive Agent Transfer Protocol [Murphy] */
+ TNET_PROTO_STP = 118, /**< STP Schedule Transfer Protocol [JMP] */
+ TNET_PROTO_SRP = 119, /**< SRP SpectraLink Radio Protocol [Hamilton] */
+ TNET_PROTO_UTI = 120, /**< UTI UTI [Lothberg] */
+ TNET_PROTO_SMP = 121, /**< SMP Simple Message Protocol [Ekblad] */
+ TNET_PROTO_SM = 122, /**< SM SM [Crowcroft] */
+ TNET_PROTO_PTP = 123, /**< PTP Performance Transparency Protocol [Welzl] */
+ TNET_PROTO_ISIS = 124, /**< ISIS over IPv4 [Przygienda] */
+ TNET_PROTO_FIRE = 125, /**< FIRE [Partridge] */
+ TNET_PROTO_CRTP = 126, /**< CRTP Combat Radio Transport Protocol [Sautter] */
+ TNET_PROTO_CRUDP = 127, /**< CRUDP Combat Radio User Datagram [Sautter] */
+ TNET_PROTO_SSCOPMCE = 128, /**< SSCOPMCE [Waber] */
+ TNET_PROTO_IPLT = 129, /**< IPLT [Hollbach] */
+ TNET_PROTO_SPS = 130, /**< SPS Secure Packet Shield [McIntosh] */
+ TNET_PROTO_PIPE = 131, /**< PIPE Private IP Encapsulation within IP [Petri] */
+ TNET_PROTO_SCTP = 132, /**< SCTP Stream Control Transmission Protocol [Stewart] */
+ TNET_PROTO_FC = 133, /**< FC Fibre Channel [Rajagopal] */
+ TNET_PROTO_RSVP_E2E_IGNORE = 134, /**< RSVP-E2E-IGNORE [RFC3175] */
+ TNET_PROTO_Mobility_Header = 135, /**< Mobility Header [RFC3775] */
+ TNET_PROTO_UDPLite = 136, /**< UDPLite [RFC3828] */
+ TNET_PROTO_MPLS_in_IP = 137, /**< MPLS-in-IP [RFC4023] */
+ TNET_PROTO_manet = 138, /**< manet MANET Protocols [RFC5498] */
+ TNET_PROTO_HIP = 139, /**< HIP Host Identity Protocol [RFC5201] */
+ TNET_PROTO_Shim6 = 140, /**< Shim6 Shim6 Protocol [RFC5533] */
+ //TNET_PROTO_ = 141-252 Unassigned [IANA]
+ TNET_PROTO_EXP1 = 253, /**< Use for experimentation and testing [RFC3692] */
+ TNET_PROTO_EXP2 = 254, /**< Use for experimentation and testing [RFC3692] */
+ TNET_PROTO_Reserved = 255, /**< Reserved [IANA] */
+
+}
+tnet_proto_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_PROTO_H */
diff --git a/tinyNET/src/tnet_socket.c b/tinyNET/src/tnet_socket.c
new file mode 100644
index 0000000..33dc807
--- /dev/null
+++ b/tinyNET/src/tnet_socket.c
@@ -0,0 +1,326 @@
+/*
+* 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.h
+ * @brief Protocol agnostic socket.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#include "tnet_socket.h"
+
+#include "tnet_utils.h"
+
+#include "tsk_string.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@defgroup tnet_socket_group Protocol agnostic socket
+*
+*
+* <h2>10.1 Sockets</h2>
+* For performance reason, all sockets created using tinyNET are non-blocking by default.
+* The newly created socket will be automatically bound to associate it with an IP address and port number. @ref tnet_socket_create() function is used to create and bind a
+* non-blocking socket. You should use @ref tnet_socket_create_2() function to control whether the socket should be bound or not. The same function is used to force the stack to create a blocking socket.<br>
+* A socket object is defined like this:<br>
+*
+* @code
+typedef struct tnet_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_socket_type_t type;
+ tnet_fd_t fd;
+ tnet_ip_t ip;
+ uint16_t port;
+
+ tnet_tls_socket_handle_t* tlshandle;
+}
+tnet_socket_t;
+* @endcode
+* To create a socket:
+* @code
+// (create udp ipv4 or ipv6 socket)
+tnet_socket_t* socket = tnet_socket_create(
+ TNET_SOCKET_HOST_ANY, // local ip address/hostname to bind to
+ TNET_SOCKET_PORT_ANY, // local port number to bind to
+ tnet_socket_type_udp_ipv46 // the socket type (IPv4 or IPv6)
+ );
+// TNET_SOCKET_HOST_ANY --> bind to "0.0.0.0" or "::"
+// TNET_SOCKET_PORT_ANY --> bind to any available port
+* @endcode
+
+* <b>TNET_SOCKET_TYPE_IS_*()</b> macros are used to determine:
+* - The socket type (stream, dgram),
+* - The socket protocol (udp, tcp, tls, sctp, ipsec),
+* - The IP version (ipv6, ipv4),
+* - …
+* <br>
+* A socket is a well-defined object and should be destroyed using @a TSK_DECLARE_SAFE_FREE() macro.
+* A socket will be automatically closed when destroyed.
+*
+*/
+
+/**@ingroup tnet_socket_group
+* Creates a new socket.
+* To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function.
+* @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string.
+* @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port.
+* @param type The type of the socket. See @ref tnet_socket_type_t.
+* @param nonblocking Indicates whether to create non-blocking socket.
+* @param bindsocket Indicates whether to bind the newly created socket or not.
+* @retval @ref tnet_socket_t object.
+* @sa @ref tnet_socket_create.
+*/
+tnet_socket_t* tnet_socket_create_2(const char*host, tnet_port_t port, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
+{
+ return tsk_object_new(tnet_socket_def_t, host, port, type, nonblocking, bindsocket);
+}
+
+/**@ingroup tnet_socket_group
+* Creates a non-blocking socket and bind it.
+* To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function.
+* @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string.
+* @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port.
+* @param type The type of the socket. See @ref tnet_socket_type_t.
+* @retval @ref tnet_socket_t object.
+*/
+tnet_socket_t* tnet_socket_create(const char* host, tnet_port_t port, tnet_socket_type_t type)
+{
+ return tnet_socket_create_2(host, port, type, tsk_true, tsk_true);
+}
+
+
+
+
+/**@ingroup tnet_socket_group
+ * Closes a socket.
+ * @param sock The socket to close.
+ * @retval Zero if succeed and nonzero error code otherwise.
+**/
+int tnet_socket_close(tnet_socket_t *sock)
+{
+ return tnet_sockfd_close(&(sock->fd));
+}
+
+int tnet_socket_set_tlsfiles(tnet_socket_tls_t* socket, int isClient, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk)
+{
+ if(socket){
+ return -1;
+ }
+
+ if(!TNET_SOCKET_TYPE_IS_TLS(socket->type)){
+ TSK_DEBUG_ERROR("Not TLS socket.");
+ return -2;
+ }
+
+ if(socket->tlshandle){
+ TSK_DEBUG_ERROR("TLS files already set.");
+ return -3;
+ }
+
+ if((socket->tlshandle = tnet_sockfd_set_tlsfiles(socket->fd, isClient, tlsfile_ca, tlsfile_pvk, tlsfile_pbk))){
+ return 0;
+ }
+ else{
+ return -4;
+ }
+}
+
+//=================================================================================================
+// SOCKET object definition
+//
+static tsk_object_t* tnet_socket_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_socket_t *sock = self;
+ if(sock){
+ int status;
+ tsk_bool_t nonblocking;
+ tsk_bool_t bindsocket;
+ tsk_istr_t port;
+ struct addrinfo *result = 0;
+ struct addrinfo *ptr = 0;
+ struct addrinfo hints;
+ tnet_host_t local_hostname;
+
+ const char *host = va_arg(*app, const char*);
+#if defined(__GNUC__)
+ sock->port = (tnet_port_t)va_arg(*app, unsigned);
+#else
+ sock->port = va_arg(*app, tnet_port_t);
+#endif
+ tsk_itoa(sock->port, &port);
+ sock->type = va_arg(*app, tnet_socket_type_t);
+ nonblocking = va_arg(*app, tsk_bool_t);
+ bindsocket = va_arg(*app, tsk_bool_t);
+
+ memset(local_hostname, 0, sizeof(local_hostname));
+
+ /* Get the local host name */
+ if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
+ memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host));
+ }
+ else{
+ if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
+ memcpy(local_hostname, "::", 2);
+ }
+ else{
+ memcpy(local_hostname, "0.0.0.0", 7);
+ }
+ //if((status = tnet_gethostname(&local_hostname)))
+ //{
+ // TNET_PRINT_LAST_ERROR("gethostname have failed.");
+ // goto bail;
+ //}
+ }
+
+ /* hints address info structure */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
+ hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
+ hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE
+#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
+ | AI_ADDRCONFIG
+#endif
+ ;
+
+ /* Performs getaddrinfo */
+ if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){
+ TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
+ hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
+ goto bail;
+ }
+
+ /* Find our address. */
+ for(ptr = result; ptr; ptr = ptr->ai_next){
+ sock->fd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
+ if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
+ continue;
+ }
+
+ if(bindsocket){
+ /* Bind the socket */
+ if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){
+ TNET_PRINT_LAST_ERROR("bind have failed.");
+ tnet_socket_close(sock);
+ continue;
+ }
+
+ /* Get local IP string. */
+ if(status = tnet_get_ip_n_port(sock->fd , &sock->ip, &sock->port)) /* % */
+ //if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
+ {
+ TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
+ tnet_socket_close(sock);
+ continue;
+ }
+// else{
+//#if TNET_UNDER_WINDOWS
+// int index;
+// if((index = tsk_strindexOf(sock->ip, tsk_strlen(sock->ip), "%")) > 0){
+// *(sock->ip + index) = '\0';
+// }
+//#endif
+// }
+ }
+
+ /* sets the real socket type (if ipv46) */
+ if(ptr->ai_family == AF_INET6) {
+ TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
+ }
+ else{
+ TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
+ }
+ break;
+ }
+
+ /* Check socket validity. */
+ if(!TNET_SOCKET_IS_VALID(sock)) {
+ TNET_PRINT_LAST_ERROR("Invalid socket.");
+ goto bail;
+ }
+
+ /* To avoid "Address already in use" error */
+ {
+#if defined(SOLARIS)
+ char yes = '1';
+#else
+ int yes = 1;
+#endif
+ if(setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int))){
+ TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR) have failed.");
+ }
+ }
+
+ /* Sets the socket to nonblocking mode */
+ if(nonblocking){
+ if((status = tnet_sockfd_set_nonblocking(sock->fd))){
+ goto bail;
+ }
+ }
+
+bail:
+ /* Free addrinfo */
+ tnet_freeaddrinfo(result);
+
+ /* Close socket if failed. */
+ if(status && TNET_SOCKET_IS_VALID(sock)){
+ tnet_socket_close(sock);
+ }
+
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_socket_dtor(tsk_object_t * self)
+{
+ tnet_socket_t *sock = self;
+
+ if(sock){
+ /* Close the socket. */
+ if(sock->fd > 0){
+ tnet_socket_close(sock);
+ }
+ /* Clean up TLS handle*/
+ if(sock->tlshandle){
+ TSK_OBJECT_SAFE_FREE(sock->tlshandle);
+ }
+ }
+
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_socket_def_s =
+{
+ sizeof(tnet_socket_t),
+ tnet_socket_ctor,
+ tnet_socket_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_socket_def_t = &tnet_socket_def_s;
+
+
diff --git a/tinyNET/src/tnet_socket.h b/tinyNET/src/tnet_socket.h
new file mode 100644
index 0000000..c29c716
--- /dev/null
+++ b/tinyNET/src/tnet_socket.h
@@ -0,0 +1,167 @@
+/*
+* 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.h
+ * @brief Protocol agnostic socket.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_SOCKET_H
+#define TNET_SOCKET_H
+
+#include "tinynet_config.h"
+#include "tnet_types.h"
+#include "tls/tnet_tls.h"
+
+#include "tsk_list.h"
+
+/** List of all supported socket types.
+* @def tnet_socket_type_e
+**/
+TNET_BEGIN_DECLS
+
+
+typedef enum tnet_socket_type_e
+{
+ tnet_socket_type_invalid = 0x0000, /**< Invalid socket.*/
+
+#define TNET_SOCKET_TYPE_IPV4 (0x0001 << 0)
+#define TNET_SOCKET_TYPE_UDP (0x0001 << 1)
+#define TNET_SOCKET_TYPE_TCP (0x0001 << 2)
+#define TNET_SOCKET_TYPE_TLS (0x0001 << 3)
+#define TNET_SOCKET_TYPE_SCTP (0x0001 << 4)
+ tnet_socket_type_udp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_UDP), /**< UDP/IPv4 socket.*/
+ tnet_socket_type_tcp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_TCP), /**< TCP/IPv4 socket.*/
+ tnet_socket_type_tls_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_TLS), /**< TLS/IPv4 socket.*/
+ tnet_socket_type_sctp_ipv4 = (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_SCTP), /**< SCTP/IPv4 socket.*/
+
+#define TNET_SOCKET_TYPE_IPSEC (0x0001 << 8)
+ tnet_socket_type_udp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv4), /**< UDP/IPSec/IPv4 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv4), /**< TCP/IPSec/IPv4 socket.*/
+ tnet_socket_type_tls_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv4), /**< TLS/IPSec /IPv4socket.*/
+ tnet_socket_type_sctp_ipsec_ipv4 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv4), /**< SCTP/IPSec/IPv4 socket.*/
+
+#define TNET_SOCKET_TYPE_IPV6 (0x0001 << 12)
+ tnet_socket_type_udp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_udp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< UDP/IPv6 socket.*/
+ tnet_socket_type_tcp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_tcp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< TCP/IPv6 socket.*/
+ tnet_socket_type_tls_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_tls_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< TLS/IPv6 socket.*/
+ tnet_socket_type_sctp_ipv6 = (TNET_SOCKET_TYPE_IPV6 | (tnet_socket_type_sctp_ipv4 ^ TNET_SOCKET_TYPE_IPV4)), /**< SCTP/IPv6 socket.*/
+ tnet_socket_type_udp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv6), /**< UDP/IPSec/IPv6 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv6), /**< TCP/IPSec/IPv6 socket.*/
+ tnet_socket_type_tls_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv6), /**< TLS/IPSec/IPv6 socket.*/
+ tnet_socket_type_sctp_ipsec_ipv6 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv6),/**< SCTP/IPSec/IPv6 socket.*/
+
+#define TNET_SOCKET_TYPE_IPV46 (TNET_SOCKET_TYPE_IPV4 | TNET_SOCKET_TYPE_IPV6)
+ tnet_socket_type_udp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_udp_ipv4 | tnet_socket_type_udp_ipv6)), /**< UDP/IPv4/6 socket.*/
+ tnet_socket_type_tcp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_tcp_ipv4 | tnet_socket_type_tcp_ipv6)), /**< TCP/IPv4/6 socket.*/
+ tnet_socket_type_tls_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_tls_ipv4 | tnet_socket_type_tls_ipv6)), /**< TLS/IPv4/6 socket.*/
+ tnet_socket_type_sctp_ipv46 = (TNET_SOCKET_TYPE_IPV46 | (tnet_socket_type_sctp_ipv4 | tnet_socket_type_sctp_ipv6)), /**< SCTP/IPv4/6 socket.*/
+ tnet_socket_type_udp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_udp_ipv46), /**< UDP/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_tcp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tcp_ipv46), /**< TCP/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_tls_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_tls_ipv46), /**< TLS/IPSec/IPv4/6 socket.*/
+ tnet_socket_type_sctp_ipsec_ipv46 = (TNET_SOCKET_TYPE_IPSEC | tnet_socket_type_sctp_ipv46),/**< SCTP/IPSec/IPv4/6 socket.*/
+}
+tnet_socket_type_t;
+
+
+/**@def TNET_SOCKET_IS_VALID
+* Checks the socket validity.
+*/
+#define TNET_SOCKET_IS_VALID(socket) ((socket) && (socket->type !=tnet_socket_type_invalid) && (socket)->fd >0)
+
+#define TNET_SOCKET_TYPE_IS_STREAM(type) ( ((type & TNET_SOCKET_TYPE_UDP) != TNET_SOCKET_TYPE_UDP) )
+#define TNET_SOCKET_TYPE_IS_DGRAM(type) ( ((type & TNET_SOCKET_TYPE_UDP) == TNET_SOCKET_TYPE_UDP) )
+
+#define TNET_SOCKET_TYPE_IS_IPV4(type) ( ((type & TNET_SOCKET_TYPE_IPV4) == TNET_SOCKET_TYPE_IPV4) )
+#define TNET_SOCKET_TYPE_IS_IPV6(type) ( ((type & TNET_SOCKET_TYPE_IPV6) == TNET_SOCKET_TYPE_IPV6) )
+#define TNET_SOCKET_TYPE_IS_IPV46(type) ( TNET_SOCKET_TYPE_IS_IPV4(type) && TNET_SOCKET_TYPE_IS_IPV6(type) )
+
+#define TNET_SOCKET_TYPE_IS_IPSEC(type) ( ((type & TNET_SOCKET_TYPE_IPSEC) == TNET_SOCKET_TYPE_IPSEC) )
+
+#define TNET_SOCKET_TYPE_IS_UDP(type) ( ((type & TNET_SOCKET_TYPE_UDP) == TNET_SOCKET_TYPE_UDP) )
+#define TNET_SOCKET_TYPE_IS_TCP(type) ( ((type & TNET_SOCKET_TYPE_TCP) == TNET_SOCKET_TYPE_TCP) )
+#define TNET_SOCKET_TYPE_IS_TLS(type) ( ((type & TNET_SOCKET_TYPE_TLS) == TNET_SOCKET_TYPE_TLS) )
+#define TNET_SOCKET_TYPE_IS_SCTP(type) ( ((type & TNET_SOCKET_TYPE_SCTP) == TNET_SOCKET_TYPE_SCTP) )
+
+#define TNET_SOCKET_TYPE_IS_SECURE(type) (TNET_SOCKET_TYPE_IS_IPSEC(type) || TNET_SOCKET_TYPE_IS_TLS(type) )
+
+#define TNET_SOCKET_TYPE_UNSET(type, OP) (type = TNET_SOCKET_TYPE_IS_##OP(type) ? type ^= TNET_SOCKET_TYPE_##OP : type)
+
+#define TNET_SOCKET_TYPE_SET_IPV4(type) (type |= TNET_SOCKET_TYPE_IPV4)
+#define TNET_SOCKET_TYPE_SET_IPV4Only(type) (type = TNET_SOCKET_TYPE_IS_IPV6(type) ? (type ^TNET_SOCKET_TYPE_IPV6)|TNET_SOCKET_TYPE_IPV4 : type)
+#define TNET_SOCKET_TYPE_SET_IPV6(type) (type |= TNET_SOCKET_TYPE_IPV6)
+#define TNET_SOCKET_TYPE_SET_IPV6Only(type) (type = TNET_SOCKET_TYPE_IS_IPV4(type) ? (type ^TNET_SOCKET_TYPE_IPV4)|TNET_SOCKET_TYPE_IPV6 : type)
+
+#define TNET_SOCKET_TYPE_SET_IPSEC(type) (type |=TNET_SOCKET_TYPE_IPSEC)
+
+#define TNET_SOCKET_TYPE_SET_UDP(type) (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,SCTP), type |=TNET_SOCKET_TYPE_UDP)
+#define TNET_SOCKET_TYPE_SET_TCP(type) (TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,SCTP), type |=TNET_SOCKET_TYPE_TCP)
+#define TNET_SOCKET_TYPE_SET_TLS(type) (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,UDP), TNET_SOCKET_TYPE_UNSET(type,SCTP), type |=TNET_SOCKET_TYPE_TLS)
+#define TNET_SOCKET_TYPE_SET_SCTP(type) (TNET_SOCKET_TYPE_UNSET(type,TCP), TNET_SOCKET_TYPE_UNSET(type,TLS), TNET_SOCKET_TYPE_UNSET(type,UDP), type |=TNET_SOCKET_TYPE_SCTP)
+
+/**
+* @def TNET_SOCKET_HOST_ANY
+* Any IPv4/IPv6 host.
+*/
+/**
+* @def TNET_SOCKET_PORT_ANY
+* Any port.
+*/
+#define TNET_SOCKET_HOST_ANY 0
+#define TNET_SOCKET_PORT_ANY 0
+
+/**
+* Socket.
+*/
+typedef struct tnet_socket_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_socket_type_t type;
+ tnet_fd_t fd;
+ tnet_ip_t ip;
+ uint16_t port;
+
+ tnet_tls_socket_handle_t* tlshandle;
+}
+tnet_socket_t;
+
+typedef tnet_socket_t tnet_socket_udp_t; /**< UDP socket. */
+typedef tnet_socket_t tnet_socket_tcp_t; /**< TCP socket. */
+typedef tnet_socket_t tnet_socket_tls_t; /**< TLS socket. */
+typedef tnet_socket_t tnet_socket_ipsec_t; /**< IPSec socket. */
+typedef tsk_list_t tnet_sockets_L_t; /**< List of @ref tnet_socket_t elements. */
+
+int tnet_socket_set_tlsfiles(tnet_socket_tls_t* socket, int isClient, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk);
+
+TINYNET_API tnet_socket_t* tnet_socket_create_2(const char*host, tnet_port_t port, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket);
+TINYNET_API tnet_socket_t* tnet_socket_create(const char* host, tnet_port_t port, tnet_socket_type_t type);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_socket_def_t;
+
+
+TNET_END_DECLS
+
+#endif /* TNET_SOCKET_H */
+
diff --git a/tinyNET/src/tnet_transport.c b/tinyNET/src/tnet_transport.c
new file mode 100644
index 0000000..75cdf85
--- /dev/null
+++ b/tinyNET/src/tnet_transport.c
@@ -0,0 +1,494 @@
+/*
+* 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_transport.c
+ * @brief Network transport layer.
+ *
+ * <h2>10.2 Tansport</h2>
+ * A transport layer always has a master socket which determine what kind of network traffic we expect (stream or dgram).
+ * Stream transport can manage TCP, TLS and SCTP sockets. Datagram socket can only manage UDP sockets. <br>
+ * A transport can hold both IPv4 and IPv6 sockets.
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_transport.h"
+
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+
+#include <string.h> /* memcpy, ...(<#void * #>, <#const void * #>, <#tsk_size_t #>) */
+
+extern int tnet_transport_prepare(tnet_transport_t *transport);
+extern int tnet_transport_unprepare(tnet_transport_t *transport);
+extern void *tnet_transport_mainthread(void *param);
+extern int tnet_transport_stop(tnet_transport_t *transport);
+
+static void *run(void* self);
+
+
+tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description)
+{
+ return tsk_object_new(tnet_transport_def_t, host, port, type, description);
+}
+
+tnet_transport_event_t* tnet_transport_event_create(tnet_transport_event_type_t type, const void* callback_data, tnet_fd_t fd)
+{
+ return tsk_object_new(tnet_transport_event_def_t, type, callback_data, fd);
+}
+
+int tnet_transport_start(tnet_transport_handle_t* handle)
+{
+ int ret = -1;
+ if(handle){
+ tnet_transport_t *transport = handle;
+
+ /* prepare transport */
+ if((ret = tnet_transport_prepare(transport))){
+ TSK_DEBUG_ERROR("Failed to prepare transport.");
+ goto bail;
+ }
+
+ /* start transport */
+ TSK_RUNNABLE(transport)->run = run;
+ if((ret = tsk_runnable_start(TSK_RUNNABLE(transport), tnet_transport_event_def_t))){
+ TSK_DEBUG_ERROR("Failed to start transport.");
+ goto bail;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+
+bail:
+ return ret;
+}
+
+int tnet_transport_issecure(const tnet_transport_handle_t *handle)
+{
+ if(handle)
+ {
+ const tnet_transport_t *transport = handle;
+ if(transport->master){
+ return TNET_SOCKET_TYPE_IS_SECURE(transport->master->type);
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return 0;
+}
+
+const char* tnet_transport_get_description(const tnet_transport_handle_t *handle)
+{
+ if(handle){
+ const tnet_transport_t *transport = handle;
+ return transport->description;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return tsk_null;
+ }
+}
+
+int tnet_transport_get_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if(handle){
+ return tnet_get_ip_n_port(fd, ip, port);
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return -1;
+}
+
+int tnet_transport_get_ip_n_port_2(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port)
+{
+ const tnet_transport_t *transport = handle;
+ if(transport){
+ // do not check the master, let the application die if "null"
+ if(ip){
+ memcpy(*ip, transport->master->ip, sizeof(transport->master->ip));
+ }
+ if(port){
+ *port = transport->master->port;
+ }
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return -1;
+ }
+}
+
+int tnet_transport_set_natt_ctx(tnet_transport_handle_t *handle, tnet_nat_context_handle_t* natt_ctx)
+{
+ tnet_transport_t *transport = handle;
+
+ if(transport && natt_ctx){
+ TSK_OBJECT_SAFE_FREE(transport->natt_ctx); // delete old
+ transport->natt_ctx = tsk_object_ref(natt_ctx);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+}
+
+int tnet_transport_get_public_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
+{
+ tsk_bool_t stun_ok = tsk_false;
+ tnet_nat_context_handle_t* natt_ctx;
+ const tnet_transport_t *transport = handle;
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if(TNET_SOCKET_TYPE_IS_DGRAM(transport->type) && (natt_ctx = tsk_object_ref(transport->natt_ctx))){
+ tnet_stun_binding_id_t bind_id = TNET_STUN_INVALID_BINDING_ID;
+ // if the socket is already monitored by the transport we should pause beacuse both the transport and
+ // NAT binder will try to read from it
+ tsk_bool_t pause_socket = (TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started);
+
+ // FIXME: change when ICE will be fully implemented
+ TSK_DEBUG_INFO("Getting public address");
+ // Pause the soket
+ if(pause_socket){
+ tnet_transport_pause_socket(transport, fd, tsk_true);
+ }
+ // Performs STUN binding
+ bind_id = tnet_nat_stun_bind(transport->natt_ctx, fd);
+ // Resume the socket
+ if(pause_socket){
+ tnet_transport_pause_socket(transport, fd, tsk_false);
+ }
+
+ if(TNET_STUN_IS_VALID_BINDING_ID(bind_id)){
+ char* public_ip = tsk_null;
+ if(tnet_nat_stun_get_reflexive_address(transport->natt_ctx, bind_id, &public_ip, port) == 0){
+ if(ip && public_ip){
+ tsk_size_t ip_len = tsk_strlen(public_ip);
+ memcpy(ip, public_ip, ip_len> sizeof(*ip)?sizeof(*ip):ip_len);
+ }
+ stun_ok = tsk_true;
+ }
+ TSK_FREE(public_ip);
+ tnet_nat_stun_unbind(transport->natt_ctx, bind_id);
+ }
+ tsk_object_unref(natt_ctx);
+ }
+
+ if(!stun_ok){
+ return tnet_transport_get_ip_n_port(handle, fd, ip, port);
+ }
+
+ return 0;
+}
+
+tnet_socket_type_t tnet_transport_get_type(const tnet_transport_handle_t *handle)
+{
+ if(handle){
+ const tnet_transport_t *transport = handle;
+ return transport->type;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return tnet_socket_type_invalid;
+}
+
+tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle)
+{
+ if(handle){
+ const tnet_transport_t *transport = handle;
+ return transport->master->fd;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ }
+ return TNET_INVALID_FD;
+}
+
+/**
+* Connects a socket.
+* @param handle The transport to use to connect() the socket. The new socket will be managed by this transport.
+* @param host The remote @a host to connect() to.
+* @param port The remote @a port to connect() to.
+* @param type The type of the socket to use to connect() to the remote @a host.
+* @retval The newly connected socket. For non-blocking sockets you should use @ref tnet_sockfd_waitUntilWritable to check
+* the socket for writability.
+* @sa tnet_sockfd_waitUntilWritable.
+*/
+tnet_fd_t tnet_transport_connectto(const tnet_transport_handle_t *handle, const char* host, tnet_port_t port, tnet_socket_type_t type)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ struct sockaddr_storage to;
+ int status = -1;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ if(!transport || !transport->master){
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ if((TNET_SOCKET_TYPE_IS_STREAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_STREAM(type)) ||
+ (TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type) && !TNET_SOCKET_TYPE_IS_DGRAM(type))){
+ TSK_DEBUG_ERROR("Master/destination types mismatch [%u/%u]", transport->master->type, type);
+ goto bail;
+ }
+
+ /* Init destination sockaddr fields */
+ if((status = tnet_sockaddr_init(host, port, type, &to))){
+ TSK_DEBUG_ERROR("Invalid HOST/PORT [%s/%u]", host, port);
+ goto bail;
+ }
+ else if(TNET_SOCKET_TYPE_IS_IPV46(type)){
+ /* Update the type (unambiguously) */
+ if(to.ss_family == AF_INET6){
+ TNET_SOCKET_TYPE_SET_IPV6Only(type);
+ }
+ else{
+ TNET_SOCKET_TYPE_SET_IPV4Only(type);
+ }
+ }
+
+ /*
+ * STREAM ==> create new socket and connect it to the remote host.
+ * DGRAM ==> connect the master to the remote host.
+ */
+ if(TNET_SOCKET_TYPE_IS_STREAM(type)){
+ /* Create client socket descriptor. */
+ if(status = tnet_sockfd_init(transport->local_ip, TNET_SOCKET_PORT_ANY, type, &fd)){
+ TSK_DEBUG_ERROR("Failed to create new sockfd.");
+ goto bail;
+ }
+
+ /* Add the socket */
+ if(status = tnet_transport_add_socket(handle, fd, type, tsk_true, tsk_true)){
+ TNET_PRINT_LAST_ERROR("Failed to add new socket.");
+
+ tnet_sockfd_close(&fd);
+ goto bail;
+ }
+ }
+ else{
+ fd = transport->master->fd;
+ }
+
+ if((status = tnet_sockfd_connectto(fd, (const struct sockaddr_storage *)&to))){
+ if(fd != transport->master->fd){
+ tnet_sockfd_close(&fd);
+ }
+ goto bail;
+ }
+ else{
+ if(TNET_SOCKET_TYPE_IS_TLS(type)){
+ transport->tls.have_tls = tsk_true;
+ /*transport->connected = !*/tnet_tls_socket_connect((tnet_tls_socket_handle_t*)tnet_transport_get_tlshandle(handle, fd));
+ }
+ else{
+ //transport->connected = tsk_true;
+ }
+ }
+
+bail:
+ return fd;
+}
+
+int tnet_transport_set_callback(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void* callback_data)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int ret = -1;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ transport->callback = callback;
+ transport->callback_data = callback_data;
+ return 0;
+}
+
+
+int tnet_transport_shutdown(tnet_transport_handle_t* handle)
+{
+ if(handle){
+ int ret;
+ if(!(ret = tnet_transport_stop(handle))){
+ ret = tnet_transport_unprepare(handle);
+ }
+ return ret;
+ }
+ else{
+ TSK_DEBUG_ERROR("NULL transport object.");
+ return -1;
+ }
+}
+
+
+
+/*
+* Runnable interface implementation.
+*/
+static void *run(void* self)
+{
+ int ret = 0;
+ tsk_list_item_t *curr;
+ tnet_transport_t *transport = self;
+
+ TSK_DEBUG_INFO("Transport::run() - enter");
+
+ /* create main thread */
+ if((ret = tsk_thread_create(transport->mainThreadId, tnet_transport_mainthread, transport))){ /* More important than "tsk_runnable_start" ==> start it first. */
+ TSK_FREE(transport->context); /* Otherwise (tsk_thread_create is ok) will be freed when mainthread exit. */
+ TSK_DEBUG_FATAL("Failed to create main thread [%d]", ret);
+ return tsk_null;
+ }
+
+ TSK_RUNNABLE_RUN_BEGIN(transport);
+
+ if((curr = TSK_RUNNABLE_POP_FIRST_SAFE(TSK_RUNNABLE(transport)))){
+ const tnet_transport_event_t *e = (const tnet_transport_event_t*)curr->data;
+
+ if(transport->callback){
+ transport->callback(e);
+ }
+ tsk_object_unref(curr);
+ }
+
+ TSK_RUNNABLE_RUN_END(transport);
+
+ TSK_DEBUG_INFO("Transport::run() - exit");
+
+ return tsk_null;
+}
+
+
+
+
+//=================================================================================================
+// Transport object definition
+//
+static tsk_object_t* tnet_transport_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_transport_t *transport = self;
+ if(transport){
+ const char *host = va_arg(*app, const char*);
+
+#if defined(__GNUC__)
+ tnet_port_t port = (uint16_t)va_arg(*app, unsigned);
+#else
+ tnet_port_t port = (tnet_port_t)va_arg(*app, tnet_port_t);
+#endif
+
+ tnet_socket_type_t type = va_arg(*app, tnet_socket_type_t);
+ const char *description = va_arg(*app, const char*);
+
+ if(description){
+ transport->description = tsk_strdup(description);
+ }
+
+ transport->type = type;
+
+ transport->master = tnet_socket_create(host, port, type);
+ transport->context = tnet_transport_context_create();
+
+ if(TNET_SOCKET_TYPE_IS_IPV46(transport->type)){
+ transport->local_ip = tsk_strdup(host); /* FQDN */
+ }
+ else{
+ transport->local_ip = tsk_strdup(transport->master->ip); /* IP address */
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_transport_dtor(tsk_object_t * self)
+{
+ tnet_transport_t *transport = self;
+ if(transport){
+ tnet_transport_shutdown(transport);
+ TSK_OBJECT_SAFE_FREE(transport->master);
+ TSK_OBJECT_SAFE_FREE(transport->context);
+ TSK_OBJECT_SAFE_FREE(transport->natt_ctx);
+ TSK_FREE(transport->description);
+ TSK_FREE(transport->local_ip);
+
+ // tls
+ TSK_FREE(transport->tls.ca);
+ TSK_FREE(transport->tls.pbk);
+ TSK_FREE(transport->tls.pvk);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_def_s =
+{
+ sizeof(tnet_transport_t),
+ tnet_transport_ctor,
+ tnet_transport_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_transport_def_t = &tnet_transport_def_s;
+
+
+
+//=================================================================================================
+// Transport event object definition
+//
+static tsk_object_t* tnet_transport_event_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_transport_event_t *e = self;
+ if(e){
+ e->type = va_arg(*app, tnet_transport_event_type_t);
+ e->callback_data = va_arg(*app, const void*);
+ e->local_fd = va_arg(*app, tnet_fd_t);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_transport_event_dtor(tsk_object_t * self)
+{
+ tnet_transport_event_t *e = self;
+ if(e){
+ TSK_FREE(e->data);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_event_def_s =
+{
+ sizeof(tnet_transport_event_t),
+ tnet_transport_event_ctor,
+ tnet_transport_event_dtor,
+ 0,
+};
+const tsk_object_def_t *tnet_transport_event_def_t = &tnet_transport_event_def_s;
+
diff --git a/tinyNET/src/tnet_transport.h b/tinyNET/src/tnet_transport.h
new file mode 100644
index 0000000..a813c09
--- /dev/null
+++ b/tinyNET/src/tnet_transport.h
@@ -0,0 +1,143 @@
+/*
+* 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_transport.h
+ * @brief Network transport layer.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_SERVER_H
+#define TNET_SERVER_H
+
+#include "tinynet_config.h"
+
+#include "tnet_socket.h"
+#include "tnet_utils.h"
+#include "tnet_nat.h"
+
+#include "tsk_runnable.h"
+
+TNET_BEGIN_DECLS
+
+#define DGRAM_MAX_SIZE 8192
+#define STREAM_MAX_SIZE 8192
+
+#define TNET_TRANSPORT_CB_F(callback) ((tnet_transport_cb_f)callback)
+
+typedef void tnet_transport_handle_t;
+
+typedef enum tnet_transport_event_type_e
+{
+ event_data,
+ event_closed,
+ event_error,
+ event_connected,
+ event_accepted
+}
+tnet_transport_event_type_t;
+
+typedef struct tnet_transport_event_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_transport_event_type_t type;
+
+ void* data;
+ tsk_size_t size;
+
+ const void* callback_data;
+ tnet_fd_t local_fd;
+ struct sockaddr_storage remote_addr;
+}
+tnet_transport_event_t;
+
+typedef int (*tnet_transport_cb_f)(const tnet_transport_event_t* e);
+
+TINYNET_API int tnet_transport_start(tnet_transport_handle_t* transport);
+TINYNET_API int tnet_transport_issecure(const tnet_transport_handle_t *handle);
+TINYNET_API const char* tnet_transport_get_description(const tnet_transport_handle_t *handle);
+TINYNET_API int tnet_transport_get_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_transport_get_ip_n_port_2(const tnet_transport_handle_t *handle, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_transport_set_natt_ctx(tnet_transport_handle_t *handle, tnet_nat_context_handle_t* natt_ctx);
+TINYNET_API int tnet_transport_get_public_ip_n_port(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port);
+
+TINYNET_API int tnet_transport_isconnected(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd);
+TINYNET_API int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient);
+TINYNET_API int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause);
+TINYNET_API int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t* fd);
+TINYNET_API tnet_fd_t tnet_transport_connectto(const tnet_transport_handle_t *handle, const char* host, tnet_port_t port, tnet_socket_type_t type);
+#define tnet_transport_connectto_2(handle, host, port) tnet_transport_connectto(handle, host, port, tnet_transport_get_type(handle))
+TINYNET_API tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size);
+TINYNET_API tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size);
+
+TINYNET_API int tnet_transport_set_callback(const tnet_transport_handle_t *handle, tnet_transport_cb_f callback, const void* callback_data);
+
+TINYNET_API tnet_socket_type_t tnet_transport_get_type(const tnet_transport_handle_t *handle);
+TINYNET_API tnet_fd_t tnet_transport_get_master_fd(const tnet_transport_handle_t *handle);
+TINYNET_API int tnet_transport_shutdown(tnet_transport_handle_t* handle);
+
+typedef struct tnet_transport_s
+{
+ TSK_DECLARE_RUNNABLE;
+
+ tnet_socket_type_t type;
+ char* local_ip;
+ tnet_nat_context_handle_t* natt_ctx;
+ tnet_socket_t *master;
+
+ tsk_object_t *context;
+ tsk_bool_t prepared;
+
+ //unsigned connected:1;
+ void* mainThreadId[1];
+
+ char *description;
+
+ tnet_transport_cb_f callback;
+ const void* callback_data;
+
+ /* TLS certs */
+ struct {
+ char* ca;
+ char* pvk;
+ char* pbk;
+ tsk_bool_t have_tls;
+ }tls;
+}
+tnet_transport_t;
+
+tsk_object_t* tnet_transport_context_create();
+TINYNET_API tnet_transport_t* tnet_transport_create(const char* host, tnet_port_t port, tnet_socket_type_t type, const char* description);
+tnet_transport_event_t* tnet_transport_event_create(tnet_transport_event_type_t type, const void* callback_data, tnet_fd_t fd);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_event_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_transport_context_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_SERVER_H */
+
diff --git a/tinyNET/src/tnet_transport_poll.c b/tinyNET/src/tnet_transport_poll.c
new file mode 100644
index 0000000..e409418
--- /dev/null
+++ b/tinyNET/src/tnet_transport_poll.c
@@ -0,0 +1,829 @@
+/*
+* 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_transport_poll.c
+ * @brief Network transport layer using polling.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_transport.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+#include "tsk_safeobj.h"
+
+#if TNET_USE_POLL
+
+#include "tnet_poll.h"
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+# import <CFNetwork/CFNetwork.h>
+#endif
+
+#define TNET_MAX_FDS 64
+
+/*== Socket description ==*/
+typedef struct transport_socket_s
+{
+ tnet_fd_t fd;
+ tsk_bool_t owner;
+ tsk_bool_t connected;
+ tsk_bool_t paused;
+
+ tnet_socket_type_t type;
+ tnet_tls_socket_handle_t* tlshandle;
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+ CFReadStreamRef cfReadStream;
+ CFWriteStreamRef cfWriteStream;
+#endif
+}
+transport_socket_t;
+
+/*== Transport context structure definition ==*/
+typedef struct transport_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t count;
+ short events;
+ tnet_fd_t pipeW;
+ tnet_fd_t pipeR;
+ tnet_pollfd_t ufds[TNET_MAX_FDS];
+ transport_socket_t* sockets[TNET_MAX_FDS];
+
+ TSK_DECLARE_SAFEOBJ;
+}
+transport_context_t;
+
+static transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd);
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client);
+static int removeSocket(int index, transport_context_t *context);
+
+
+int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t* context;
+ static char c = '\0';
+ int ret = -1;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ if(TNET_SOCKET_TYPE_IS_TLS(type)){
+ transport->tls.have_tls = 1;
+ }
+
+ if((ret = addSocket(fd, type, transport, take_ownership, isClient))){
+ TSK_DEBUG_ERROR("Failed to add new Socket.");
+ return ret;
+ }
+
+ // signal
+ if(context->pipeW){
+ if((ret = write(context->pipeW, &c, 1)) > 0){
+ TSK_DEBUG_INFO("Socket added (external call) %d", fd);
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Failed to add new Socket.");
+ return ret;
+ }
+ }else{
+ TSK_DEBUG_WARN("pipeW (write site) not initialized yet.");
+ return 0; //Will be taken when mainthead start
+ }
+}
+
+int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ transport_socket_t* socket;
+
+ if(!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((socket = getSocket(context, fd))){
+ socket->paused = pause;
+ }
+ else{
+ TSK_DEBUG_WARN("Socket does not exist in this context");
+ }
+ return 0;
+}
+
+/* Remove socket */
+int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t *fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ int ret = -1;
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+
+ TSK_DEBUG_INFO("Removing socket %d", *fd);
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == *fd){
+ removeSocket(i, context);
+ found = tsk_true;
+ *fd = TNET_INVALID_FD;
+ break;
+ }
+ }
+
+ if(found){
+ /* Signal */
+ static char c = '\0';
+ ret = write(context->pipeW, &c, 1);
+ return (ret > 0 ? 0 : ret);
+ }
+
+ // ...
+
+ return -1;
+}
+
+
+tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ if(transport->tls.have_tls){
+ const transport_socket_t* socket = getSocket(transport->context, from);
+ if(socket && socket->tlshandle){
+ if(!tnet_tls_socket_send(socket->tlshandle, buf, size)){
+ numberOfBytesSent = size;
+ }
+ else{
+ numberOfBytesSent = 0;
+ }
+ goto bail;
+ }
+ }
+ else if((numberOfBytesSent = send(from, buf, size, 0)) <= 0){
+ TNET_PRINT_LAST_ERROR("send have failed.");
+
+ //tnet_sockfd_close(&from);
+ goto bail;
+ }
+
+bail:
+ return numberOfBytesSent;
+}
+
+tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int numberOfBytesSent = 0;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ goto bail;
+ }
+
+ if(!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)){
+ TSK_DEBUG_ERROR("In order to use sendto() you must use an udp transport.");
+ goto bail;
+ }
+
+ if((numberOfBytesSent = sendto(from, buf, size, 0, to, tnet_get_sockaddr_size(to))) <= 0){
+ TNET_PRINT_LAST_ERROR("sendto have failed.");
+ goto bail;
+ }
+
+bail:
+ return numberOfBytesSent;
+}
+
+int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ return (getSocket((transport_context_t*)transport->context, fd) != 0);
+}
+
+const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ const transport_socket_t *socket;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ if((socket = getSocket((transport_context_t*)transport->context, fd))){
+ return socket->tlshandle;
+ }
+ return 0;
+}
+
+
+/*== Get socket ==*/
+static transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd)
+{
+ tsk_size_t i;
+ transport_socket_t* ret = 0;
+
+ if(context){
+ tsk_safeobj_lock(context);
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == fd){
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+
+/*== Add new socket ==*/
+int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, tsk_bool_t take_ownership, tsk_bool_t is_client)
+{
+ transport_context_t *context = transport?transport->context:0;
+ if(context){
+ transport_socket_t *sock = tsk_calloc(1, sizeof(transport_socket_t));
+ sock->fd = fd;
+ sock->type = type;
+ sock->owner = take_ownership;
+
+ if(TNET_SOCKET_TYPE_IS_TLS(sock->type)){
+ sock->tlshandle = tnet_sockfd_set_tlsfiles(sock->fd, is_client, transport->tls.ca, transport->tls.pvk, transport->tls.pbk);
+ }
+
+ tsk_safeobj_lock(context);
+
+ context->ufds[context->count].fd = fd;
+ context->ufds[context->count].events = (fd == context->pipeR) ? TNET_POLLIN : context->events;
+ context->ufds[context->count].revents = 0;
+ context->sockets[context->count] = sock;
+
+ context->count++;
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+ if(context->pipeR != sock->fd){
+ if(TNET_SOCKET_TYPE_IS_DGRAM(sock->type)){
+ CFSocketRef cfSocket;
+
+ cfSocket = CFSocketCreateWithNative(kCFAllocatorDefault,
+ sock->fd,
+ kCFSocketReadCallBack,
+ tsk_null,
+ tsk_null);
+
+ // Don't close the socket if the CFSocket is invalidated
+ CFOptionFlags flags = CFSocketGetSocketFlags(cfSocket);
+ flags = flags & ~kCFSocketCloseOnInvalidate;
+ CFSocketSetSocketFlags(cfSocket, flags);
+
+ if (CFSocketIsValid(cfSocket)) {
+ CFSocketInvalidate(cfSocket);
+ }
+ CFRelease(cfSocket);
+ }
+ else if(TNET_SOCKET_TYPE_IS_STREAM(sock->type)){
+ CFStreamCreatePairWithSocket(kCFAllocatorDefault, (CFSocketNativeHandle)sock->fd, &sock->cfReadStream, &sock->cfWriteStream);
+
+ CFReadStreamSetProperty(sock->cfReadStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
+ CFWriteStreamSetProperty(sock->cfWriteStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanFalse);
+
+ if(!CFReadStreamSetProperty(sock->cfReadStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){
+ //TNET_PRINT_LAST_ERROR("CFReadStreamSetProperty(cfReadStream, kCFStreamNetworkServiceTypeVoIP) failed");
+ }
+ if(!CFWriteStreamSetProperty(sock->cfWriteStream, kCFStreamNetworkServiceType, kCFStreamNetworkServiceTypeVoIP)){
+ //TNET_PRINT_LAST_ERROR("CFReadStreamSetProperty(cfWriteStream, kCFStreamNetworkServiceTypeVoIP) failed");
+ }
+ }
+
+ if(sock->cfReadStream){
+ if(!CFReadStreamOpen(sock->cfReadStream)){
+ //TNET_PRINT_LAST_ERROR("CFReadStreamOpen(cfWriteStream) failed");
+ }
+ }
+ if(sock->cfWriteStream){
+ if(!CFWriteStreamOpen(sock->cfWriteStream)){
+ //TNET_PRINT_LAST_ERROR("CFWriteStreamOpen(cfWriteStream) failed");
+ }
+ }
+ }
+#endif
+
+ tsk_safeobj_unlock(context);
+
+ TSK_DEBUG_INFO("Socket added %d", fd);
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Context is Null.");
+ return -1;
+ }
+}
+
+/*== change connection state ==*/
+/*
+static void setConnected(tnet_fd_t fd, transport_context_t *context, int connected)
+{
+ tsk_size_t i;
+
+ for(i=0; i<context->count; i++)
+ {
+ if(context->sockets[i]->fd == fd){
+ context->sockets[i]->connected = connected;
+ }
+ }
+}
+*/
+
+/*== Remove socket ==*/
+int removeSocket(int index, transport_context_t *context)
+{
+ int i;
+
+ tsk_safeobj_lock(context);
+
+ if(index < (int)context->count){
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
+ // Even if we are not the owner as CFSocket is only supported at low level
+ if(context->sockets[index]->cfReadStream){
+ CFReadStreamClose(context->sockets[index]->cfReadStream);
+ CFRelease(context->sockets[index]->cfReadStream);
+ }
+ if(context->sockets[index]->cfWriteStream){
+ CFWriteStreamClose(context->sockets[index]->cfWriteStream);
+ CFRelease(context->sockets[index]->cfWriteStream);
+ }
+#endif
+ /* Close the socket if we are the owner. */
+ if(context->sockets[index]->owner){
+ tnet_sockfd_close(&(context->sockets[index]->fd));
+ }
+
+ /* Free tls context */
+ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle);
+
+ // Free socket
+ TSK_FREE(context->sockets[index]);
+
+ for(i=index ; i<context->count-1; i++){
+ context->sockets[i] = context->sockets[i+1];
+ context->ufds[i] = context->ufds[i+1];
+ }
+
+ context->sockets[context->count-1] = tsk_null;
+ context->ufds[context->count-1].fd = 0;
+ context->ufds[context->count-1].events = 0;
+ context->ufds[context->count-1].revents = 0;
+
+ context->count--;
+ TSK_DEBUG_INFO("Socket removed");
+ }
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+int tnet_transport_stop(tnet_transport_t *transport)
+{
+ int ret;
+ transport_context_t *context;
+
+ if(!transport){
+ return -1;
+ }
+
+ context = transport->context;
+
+ if((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))){
+ return ret;
+ }
+
+ if(context){
+ static char c = '\0';
+
+ // signal
+ tsk_safeobj_lock(context); // =>MUST
+ if(tnet_transport_have_socket(transport, context->pipeR)){ // to avoid SIGPIPE=> check that there is at least one reader
+ write(context->pipeW, &c, 1);
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ if(transport->mainThreadId[0]){
+ return tsk_thread_join(transport->mainThreadId);
+ }
+ else{
+ /* already soppped */
+ return 0;
+ }
+}
+
+int tnet_transport_prepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+ tnet_fd_t pipes[2];
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(transport->prepared){
+ TSK_DEBUG_ERROR("Transport already prepared.");
+ return -2;
+ }
+
+ /* set events */
+ context->events = TNET_POLLIN | TNET_POLLNVAL | TNET_POLLERR;
+ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){
+ context->events |= TNET_POLLOUT // emulate WinSock2 FD_CONNECT event
+//#if !defined(ANDROID)
+// | TNET_POLLHUP /* FIXME: always present */
+//#endif
+ ;
+ }
+
+ /* Start listening */
+ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){
+ if((ret = tnet_sockfd_listen(transport->master->fd, TNET_MAX_FDS))){
+ TNET_PRINT_LAST_ERROR("listen have failed.");
+ goto bail;
+ }
+ }
+
+ /* Create and add pipes to the fd_set */
+ if((ret = pipe(pipes))){
+ TNET_PRINT_LAST_ERROR("Failed to create new pipes.");
+ goto bail;
+ }
+
+ /* set both R and W sides */
+ context->pipeR = pipes[0];
+ context->pipeW = pipes[1];
+
+ /* add R side */
+ TSK_DEBUG_INFO("pipeR fd=%d", context->pipeR);
+ if((ret = addSocket(context->pipeR, transport->master->type, transport, tsk_true, tsk_false))){
+ goto bail;
+ }
+
+ /* Add the master socket to the context. */
+ TSK_DEBUG_INFO("master fd=%d", transport->master->fd);
+ if((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_true, tsk_false))){
+ TSK_DEBUG_ERROR("Failed to add master socket");
+ goto bail;
+ }
+
+ transport->prepared = tsk_true;
+
+bail:
+ return ret;
+}
+
+int tnet_transport_unprepare(tnet_transport_t *transport)
+{
+ //int ret = -1;
+ transport_context_t *context;
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(!transport->prepared){
+ return 0;
+ }
+
+ transport->prepared = tsk_false;
+
+ while(context->count){
+ removeSocket(0, context); // safe
+ }
+
+ return 0;
+}
+
+/*=== Main thread */
+void *tnet_transport_mainthread(void *param)
+{
+ tnet_transport_t *transport = param;
+ transport_context_t *context = transport->context;
+ int ret;
+ tsk_size_t i;
+
+ transport_socket_t* active_socket;
+
+ /* check whether the transport is already prepared */
+ if(!transport->prepared){
+ TSK_DEBUG_ERROR("Transport must be prepared before strating.");
+ goto bail;
+ }
+
+ TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
+
+ while(TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started){
+ if((ret = tnet_poll(context->ufds, context->count, -1)) < 0){
+ TNET_PRINT_LAST_ERROR("poll have failed.");
+ goto bail;
+ }
+
+ if(!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started){
+ TSK_DEBUG_INFO("Stopping [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
+ goto bail;
+ }
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ /* == == */
+ for(i=0; i<context->count; i++)
+ {
+ if(!context->ufds[i].revents){
+ continue;
+ }
+
+ if(context->ufds[i].fd == context->pipeR){
+ TSK_DEBUG_INFO("PipeR event %d", context->ufds[i].revents);
+ if(context->ufds[i].revents & TNET_POLLIN){
+ static char __buffer[64];
+ if(read(context->pipeR, __buffer, sizeof(__buffer))<0){
+ TNET_PRINT_LAST_ERROR("Failed to read from the Pipe");
+ }
+ }
+ else if(context->ufds[i].revents & TNET_POLLHUP){
+ TNET_PRINT_LAST_ERROR("Pipe Error");
+ goto bail;
+ }
+ context->ufds[i].revents = 0;
+ continue;
+ }
+
+ /* Get active event and socket */
+ active_socket = context->sockets[i];
+
+ /*================== POLLIN ==================*/
+ if(context->ufds[i].revents & TNET_POLLIN)
+ {
+ tsk_size_t len = 0;
+ void* buffer = tsk_null;
+ tnet_transport_event_t* e;
+
+ //--TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLIN", transport->description);
+
+ //
+ // FIXME: check if accept() is needed or not
+ //
+
+
+ /* check whether the socket is paused or not */
+ if(active_socket->paused){
+ TSK_DEBUG_INFO("Socket is paused");
+ goto TNET_POLLIN_DONE;
+ }
+
+ /* Retrieve the amount of pending data.
+ * IMPORTANT: If you are using Symbian please update your SDK to the latest build (August 2009) to have 'FIONREAD'.
+ * This apply whatever you are using the 3rd or 5th edition.
+ * Download link: http://wiki.forum.nokia.com/index.php/Open_C/C%2B%2B_Release_History
+ */
+ if(tnet_ioctlt(active_socket->fd, FIONREAD, &len) < 0){
+ /* It's probably an incoming connection --> try to accept() it */
+ tnet_fd_t fd;
+ if((fd = accept(active_socket->fd, tsk_null, 0)) != TNET_INVALID_SOCKET){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT(fd=%d)", transport->description, fd);
+ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false);
+ TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("IOCTLT FAILED.");
+ tnet_transport_remove_socket(transport, &active_socket->fd);
+ continue;
+ }
+ }
+
+ if(!len){
+ TSK_DEBUG_WARN("IOCTLT returned zero for fd=%d", active_socket->fd);
+#if defined(ANDROID) || 1 /* FIXME: On Android/MAC OS X this mean that the socket has been closed? */
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd);
+ removeSocket(i, context);
+#else
+ recv(active_socket->fd, 0, 0, 0);
+#endif
+ continue;
+
+ }
+
+ if(!(buffer = tsk_calloc(len, sizeof(uint8_t)))){
+ TSK_DEBUG_ERROR("TSK_CALLOC FAILED.");
+ continue;
+ }
+
+
+ /* Receive the waiting data. */
+ if(active_socket->tlshandle){
+ int isEncrypted;
+ tsk_size_t tlslen = len;
+ if((ret = tnet_tls_socket_recv(active_socket->tlshandle, &buffer, &tlslen, &isEncrypted)) == 0){
+ if(isEncrypted){
+ TSK_FREE(buffer);
+ continue;
+ }
+ len = tlslen;
+ }
+ }
+ else if((ret = tnet_sockfd_recv(active_socket->fd, buffer, len, 0)) < 0){
+ TSK_FREE(buffer);
+
+ removeSocket(i, context);
+ TNET_PRINT_LAST_ERROR("recv have failed.");
+ continue;
+ }
+ else if((len != (tsk_size_t)ret) && len){ /* useless test? */
+ len = (tsk_size_t)ret;
+ /* buffer = tsk_realloc(buffer, len); */
+ }
+
+ e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
+ e->data = buffer;
+ e->size = len;
+
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+
+TNET_POLLIN_DONE:;
+ }
+
+
+ /*================== TNET_POLLOUT ==================*/
+ if(context->ufds[i].revents & TNET_POLLOUT){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLOUT", transport->description);
+ if(!active_socket->connected){
+ active_socket->connected = tsk_true;
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
+ }
+ context->ufds[i].events &= ~TNET_POLLOUT;
+ }
+
+
+ /*================== TNET_POLLPRI ==================*/
+ if(context->ufds[i].revents & TNET_POLLPRI){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLPRI", transport->description);
+ }
+
+ /*================== TNET_POLLHUP ==================*/
+ if(context->ufds[i].revents & (TNET_POLLHUP)){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLHUP", transport->description);
+#if defined(ANDROID)
+ /* FIXME */
+#else
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd);
+ removeSocket(i, context);
+#endif
+ }
+
+ /*================== TNET_POLLERR ==================*/
+ if(context->ufds[i].revents & (TNET_POLLERR)){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLERR", transport->description);
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ removeSocket(i, context);
+ }
+
+ /*================== TNET_POLLNVAL ==================*/
+ if(context->ufds[i].revents & (TNET_POLLNVAL)){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- TNET_POLLNVAL", transport->description);
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ removeSocket(i, context);
+ }
+
+
+ }/* for */
+
+done:
+ /* unlock context */
+ tsk_safeobj_unlock(context);
+
+ } /* while */
+
+bail:
+
+ TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}", transport->description, transport->master->ip, transport->master->port);
+ return 0;
+}
+
+
+
+
+
+
+
+
+void* tnet_transport_context_create()
+{
+ return tsk_object_new(tnet_transport_context_def_t);
+}
+
+
+//=================================================================================================
+// Transport context object definition
+//
+static tsk_object_t* transport_context_ctor(tsk_object_t * self, va_list * app)
+{
+ transport_context_t *context = self;
+ if(context){
+ tsk_safeobj_init(context);
+ }
+ return self;
+}
+
+static tsk_object_t* transport_context_dtor(tsk_object_t * self)
+{
+ transport_context_t *context = self;
+ if(context){
+ while(context->count){
+ removeSocket(0, context);
+ }
+ tsk_safeobj_deinit(context);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_context_def_s =
+{
+sizeof(transport_context_t),
+transport_context_ctor,
+transport_context_dtor,
+tsk_null,
+};
+const tsk_object_def_t *tnet_transport_context_def_t = &tnet_transport_context_def_s;
+
+#endif /* HAVE_POLL_H */
+
+
diff --git a/tinyNET/src/tnet_transport_win32.c b/tinyNET/src/tnet_transport_win32.c
new file mode 100644
index 0000000..baa745d
--- /dev/null
+++ b/tinyNET/src/tnet_transport_win32.c
@@ -0,0 +1,786 @@
+/*
+* 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_transport_win32.c
+ * @brief Network transport layer for WIN32(XP/Vista/7) and WINCE(5.0 or higher) systems.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_transport.h"
+#include "tsk_memory.h"
+#include "tsk_string.h"
+#include "tsk_debug.h"
+#include "tsk_thread.h"
+#include "tsk_buffer.h"
+#include "tsk_safeobj.h"
+
+#if TNET_UNDER_WINDOWS && !TNET_USE_POLL
+
+/*== Socket description ==*/
+typedef struct transport_socket_s
+{
+ tnet_fd_t fd;
+ unsigned owner:1;
+ unsigned connected:1;
+ unsigned paused:1;
+
+ tnet_socket_type_t type;
+ tnet_tls_socket_handle_t* tlshandle;
+}
+transport_socket_t;
+
+/*== Transport context structure definition ==*/
+typedef struct transport_context_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tsk_size_t count;
+ WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];
+ transport_socket_t* sockets[WSA_MAXIMUM_WAIT_EVENTS];
+
+ TSK_DECLARE_SAFEOBJ;
+}
+transport_context_t;
+
+static transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd);
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, int take_ownership, int is_client);
+static int removeSocket(int index, transport_context_t *context);
+
+/* Checks if socket is connected */
+int tnet_transport_isconnected(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ tsk_size_t i;
+
+ if(!transport)
+ {
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ context = (transport_context_t*)transport->context;
+ for(i=0; i<context->count; i++)
+ {
+ const transport_socket_t* socket = context->sockets[i];
+ if(socket->fd == fd){
+ return socket->connected;
+ }
+ }
+
+ return 0;
+}
+
+int tnet_transport_have_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ return (getSocket((transport_context_t*)transport->context, fd) != 0);
+}
+
+const tnet_tls_socket_handle_t* tnet_transport_get_tlshandle(const tnet_transport_handle_t *handle, tnet_fd_t fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_socket_t *socket;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return 0;
+ }
+
+ if((socket = getSocket((transport_context_t*)transport->context, fd))){
+ return socket->tlshandle;
+ }
+ return 0;
+}
+
+/*
+* Add new socket to the watcher.
+*/
+int tnet_transport_add_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tnet_socket_type_t type, tsk_bool_t take_ownership, tsk_bool_t isClient)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t* context;
+ int ret = -1;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid context.");
+ return -2;
+ }
+
+ if(TNET_SOCKET_TYPE_IS_TLS(type)){
+ transport->tls.have_tls = 1;
+ }
+
+ addSocket(fd, type, transport, take_ownership, isClient);
+ if(WSAEventSelect(fd, context->events[context->count - 1], FD_ALL_EVENTS) == SOCKET_ERROR){
+ removeSocket((context->count - 1), context);
+ TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
+ return -1;
+ }
+
+ /* Signal */
+ if(WSASetEvent(context->events[0])){
+ TSK_DEBUG_INFO("New socket added to the network transport.");
+ return 0;
+ }
+
+ // ...
+
+ return -1;
+}
+
+int tnet_transport_pause_socket(const tnet_transport_handle_t *handle, tnet_fd_t fd, tsk_bool_t pause)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ transport_socket_t* socket;
+
+ if(!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ if((socket = getSocket(context, fd))){
+ socket->paused = pause;
+ }
+ else{
+ TSK_DEBUG_WARN("Socket does not exist in this context");
+ }
+ return 0;
+}
+
+/* Remove socket
+*/
+int tnet_transport_remove_socket(const tnet_transport_handle_t *handle, tnet_fd_t* fd)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ transport_context_t *context;
+ int ret = -1;
+ tsk_size_t i;
+ tsk_bool_t found = tsk_false;
+
+ if(!transport || !(context = (transport_context_t*)transport->context)){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ return -1;
+ }
+
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == *fd){
+ removeSocket(i, context);
+ found = tsk_true;
+ *fd = TNET_INVALID_FD;
+ break;
+ }
+ }
+
+ if(found){
+ /* Signal */
+ if(WSASetEvent(context->events[0])){
+ TSK_DEBUG_INFO("Old socket removed from the network transport.");
+ return 0;
+ }
+ }
+
+ // ...
+
+ return -1;
+}
+
+/*
+* Sends stream/dgram data to the remote peer (shall be previously connected using @tnet_transport_connectto).
+*/
+tsk_size_t tnet_transport_send(const tnet_transport_handle_t *handle, tnet_fd_t from, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ int ret = -1;
+ DWORD numberOfBytesSent = 0;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid transport handle.");
+ goto bail;
+ }
+
+ if(transport->tls.have_tls){
+ transport_socket_t* socket = getSocket(transport->context, from);
+ if(socket && socket->tlshandle){
+ if(!tnet_tls_socket_send(socket->tlshandle, buf, size)){
+ numberOfBytesSent = size;
+ }
+ else{
+ numberOfBytesSent = 0;
+ }
+ goto bail;
+ }
+ }
+ else{
+ WSABUF wsaBuffer;
+ wsaBuffer.buf = (CHAR*)buf;
+ wsaBuffer.len = size;
+
+ if((ret = WSASend(from, &wsaBuffer, 1, &numberOfBytesSent, 0, NULL, NULL)) == SOCKET_ERROR){
+ if((ret = WSAGetLastError()) == WSA_IO_PENDING){
+ TSK_DEBUG_INFO("WSA_IO_PENDING error for WSASend SSESSION");
+ ret = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("WSASend have failed.");
+
+ //tnet_sockfd_close(&from);
+ goto bail;
+ }
+ }
+ else{
+ ret = 0;
+ }
+ }
+
+bail:
+ return numberOfBytesSent;
+}
+
+/*
+* Sends dgarm to the specified destionation.
+*/
+tsk_size_t tnet_transport_sendto(const tnet_transport_handle_t *handle, tnet_fd_t from, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tnet_transport_t *transport = (tnet_transport_t*)handle;
+ WSABUF wsaBuffer;
+ DWORD numberOfBytesSent = 0;
+ int ret = -1;
+
+ if(!transport){
+ TSK_DEBUG_ERROR("Invalid server handle.");
+ return ret;
+ }
+
+ if(!TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)){
+ TSK_DEBUG_ERROR("In order to use WSASendTo you must use an udp transport.");
+ return ret;
+ }
+
+ wsaBuffer.buf = (CHAR*)buf;
+ wsaBuffer.len = size;
+
+ if((ret = WSASendTo(from, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0)) == SOCKET_ERROR){
+ if((ret = WSAGetLastError()) == WSA_IO_PENDING){
+ TSK_DEBUG_INFO("WSA_IO_PENDING error for WSASendTo SSESSION");
+ ret = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("WSASendTo have failed.");
+ return ret;
+ }
+ } else ret = 0;
+
+ return numberOfBytesSent;
+}
+
+
+
+
+
+
+
+
+/*== CAllback function to check if we should accept the new socket or not == */
+int CALLBACK AcceptCondFunc(LPWSABUF lpCallerId, LPWSABUF lpCallerData, LPQOS lpSQos, LPQOS lpGQos, LPWSABUF lpCalleeId, LPWSABUF lpCalleeData, GROUP FAR *Group, DWORD CallbackData)
+{
+ transport_context_t *context = (transport_context_t*)CallbackData;
+ return context->count < WSA_MAXIMUM_WAIT_EVENTS ? CF_ACCEPT : CF_REJECT;
+}
+
+/*== Get socket ==*/
+static transport_socket_t* getSocket(transport_context_t *context, tnet_fd_t fd)
+{
+ tsk_size_t i;
+ transport_socket_t* ret = 0;
+
+ if(context){
+ tsk_safeobj_lock(context);
+ for(i=0; i<context->count; i++){
+ if(context->sockets[i]->fd == fd){
+ ret = context->sockets[i];
+ break;
+ }
+ }
+ tsk_safeobj_unlock(context);
+ }
+
+ return ret;
+}
+
+/*== Add new socket ==*/
+static int addSocket(tnet_fd_t fd, tnet_socket_type_t type, tnet_transport_t *transport, int take_ownership, int is_client)
+{
+ transport_context_t *context = transport?transport->context:0;
+
+ if(context){
+ transport_socket_t *sock = tsk_calloc(1, sizeof(transport_socket_t));
+ sock->fd = fd;
+ sock->type = type;
+ sock->owner = take_ownership ? 1 : 0;
+
+ if(TNET_SOCKET_TYPE_IS_TLS(sock->type)){
+ sock->tlshandle = tnet_sockfd_set_tlsfiles(sock->fd, is_client, transport->tls.ca, transport->tls.pvk, transport->tls.pbk);
+ }
+
+ tsk_safeobj_lock(context);
+ context->events[context->count] = WSACreateEvent();
+ context->sockets[context->count] = sock;
+
+ context->count++;
+ tsk_safeobj_unlock(context);
+
+ return 0;
+ }
+ else{
+ TSK_DEBUG_ERROR("Context is Null.");
+ return -1;
+ }
+}
+
+/*== Remove socket ==*/
+static int removeSocket(int index, transport_context_t *context)
+{
+ tsk_size_t i;
+
+ tsk_safeobj_lock(context);
+
+ if(index < (int)context->count){
+
+ /* Close the socket if we are the owner. */
+ if(context->sockets[index]->owner){
+ tnet_sockfd_close(&(context->sockets[index]->fd));
+ }
+
+ /* Free tls context */
+ if(context->sockets[index]->tlshandle){
+ TSK_OBJECT_SAFE_FREE(context->sockets[index]->tlshandle);
+ }
+ // Free socket
+ TSK_FREE(context->sockets[index]);
+
+ // Close event
+ WSACloseEvent(context->events[index]);
+
+ for(i=index ; i<context->count-1; i++){
+ context->sockets[i] = context->sockets[i+1];
+ context->events[i] = context->events[i+1];
+ }
+
+ context->sockets[context->count-1] = 0;
+ context->events[context->count-1] = 0;
+
+ context->count--;
+ }
+
+ tsk_safeobj_unlock(context);
+
+ return 0;
+}
+
+/*=== stop all threads */
+int tnet_transport_stop(tnet_transport_t *transport)
+{
+ int ret;
+
+ if((ret = tsk_runnable_stop(TSK_RUNNABLE(transport)))){
+ return ret;
+ }
+
+ if(transport->mainThreadId[0]){
+ WSASetEvent(((transport_context_t*)(transport->context))->events[0]);
+ return tsk_thread_join(transport->mainThreadId);
+ }
+ else{
+ /* already stoppped */
+ return 0;
+ }
+}
+
+
+int tnet_transport_prepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(transport->prepared){
+ TSK_DEBUG_ERROR("Transport already prepared.");
+ return -2;
+ }
+
+ /* Start listening */
+ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){
+ if((ret = tnet_sockfd_listen(transport->master->fd, WSA_MAXIMUM_WAIT_EVENTS))){
+ TNET_PRINT_LAST_ERROR("listen have failed.");
+ goto bail;
+ }
+ }
+
+ /* Add the master socket to the context. */
+ if((ret = addSocket(transport->master->fd, transport->master->type, transport, tsk_true, tsk_false))){
+ TSK_DEBUG_ERROR("Failed to add master socket");
+ goto bail;
+ }
+
+ /* set events on master socket */
+ if((ret = WSAEventSelect(transport->master->fd, context->events[context->count - 1], TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type) ? FD_READ : FD_ALL_EVENTS/*FD_ACCEPT | FD_READ | FD_CONNECT | FD_CLOSE*/) == SOCKET_ERROR)){
+ TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
+ goto bail;
+ }
+
+ transport->prepared = tsk_true;
+
+bail:
+ return ret;
+}
+
+int tnet_transport_unprepare(tnet_transport_t *transport)
+{
+ int ret = -1;
+ transport_context_t *context;
+
+ if(!transport || !transport->context){
+ TSK_DEBUG_ERROR("Invalid parameter.");
+ return -1;
+ }
+ else{
+ context = transport->context;
+ }
+
+ if(!transport->prepared){
+ return 0;
+ }
+
+ transport->prepared = tsk_false;
+
+ while(context->count){
+ removeSocket(0, context); // safe
+ }
+
+ return 0;
+}
+
+/*=== Main thread */
+void *tnet_transport_mainthread(void *param)
+{
+ tnet_transport_t *transport = param;
+ transport_context_t *context = transport->context;
+ DWORD evt;
+ WSANETWORKEVENTS networkEvents;
+ DWORD flags = 0;
+ int ret;
+
+ struct sockaddr_storage remote_addr = {0};
+ WSAEVENT active_event;
+ transport_socket_t* active_socket;
+ int index;
+
+ TSK_DEBUG_INFO("Starting [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
+
+ while(TSK_RUNNABLE(transport)->running || TSK_RUNNABLE(transport)->started)
+ {
+ /* Wait for multiple events */
+ if((evt = WSAWaitForMultipleEvents(context->count, context->events, FALSE, WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED){
+ TNET_PRINT_LAST_ERROR("WSAWaitForMultipleEvents have failed.");
+ goto bail;
+ }
+
+ if(!TSK_RUNNABLE(transport)->running && !TSK_RUNNABLE(transport)->started){
+ goto bail;
+ }
+
+ /* lock context */
+ tsk_safeobj_lock(context);
+
+ /* Get active event and socket */
+ index = (evt - WSA_WAIT_EVENT_0);
+ active_event = context->events[index];
+ if(!(active_socket = context->sockets[index])){
+ goto done;
+ }
+
+ /* Get the network events flags */
+ if (WSAEnumNetworkEvents(active_socket->fd, active_event, &networkEvents) == SOCKET_ERROR){
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("WSAEnumNetworkEvents have failed.");
+
+ tsk_safeobj_unlock(context);
+ goto bail;
+ }
+
+ /*================== FD_ACCEPT ==================*/
+ if(networkEvents.lNetworkEvents & FD_ACCEPT)
+ {
+ tnet_fd_t fd;
+
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_ACCEPT", transport->description);
+
+ if(networkEvents.iErrorCode[FD_ACCEPT_BIT]){
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
+ goto done;
+ }
+
+ /* Accept the connection */
+ if((fd = WSAAccept(active_socket->fd, NULL, NULL, AcceptCondFunc, (DWORD_PTR)context)) != INVALID_SOCKET){
+ /* Add the new fd to the server context */
+ addSocket(fd, transport->master->type, transport, tsk_true, tsk_false);
+ if(WSAEventSelect(fd, context->events[context->count - 1], FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR){
+ removeSocket((context->count - 1), context);
+ TNET_PRINT_LAST_ERROR("WSAEventSelect have failed.");
+ goto done;
+ }
+ TSK_RUNNABLE_ENQUEUE(transport, event_accepted, transport->callback_data, fd);
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("ACCEPT FAILED.");
+ goto done;
+ }
+
+
+
+
+ }
+
+ /*================== FD_CONNECT ==================*/
+ if(networkEvents.lNetworkEvents & FD_CONNECT)
+ {
+ //tnet_fd_t fd;
+
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CONNECT", transport->description);
+
+ if(networkEvents.iErrorCode[FD_CONNECT_BIT]){
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("CONNECT FAILED.");
+ goto done;
+ }
+ else{
+ TSK_RUNNABLE_ENQUEUE(transport, event_connected, transport->callback_data, active_socket->fd);
+ active_socket->connected = 1;
+ }
+ }
+
+
+ /*================== FD_READ ==================*/
+ if(networkEvents.lNetworkEvents & FD_READ)
+ {
+ DWORD readCount = 0;
+ WSABUF wsaBuffer;
+
+ /* TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_READ", transport->description); */
+
+ /* check whether the socket is paused or not */
+ if(active_socket->paused){
+ TSK_DEBUG_INFO("Socket is paused");
+ goto FD_READ_DONE;
+ }
+
+ if(networkEvents.iErrorCode[FD_READ_BIT]){
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("READ FAILED.");
+ goto done;
+ }
+
+ /* Retrieve the amount of pending data */
+ if(tnet_ioctlt(active_socket->fd, FIONREAD, &(wsaBuffer.len)) < 0){
+ TNET_PRINT_LAST_ERROR("IOCTLT FAILED.");
+ goto done;
+ }
+
+ if(!wsaBuffer.len){
+ goto done;
+ }
+
+ /* Alloc data */
+ if(!(wsaBuffer.buf = tsk_calloc(wsaBuffer.len, sizeof(uint8_t)))){
+ goto done;
+ }
+
+ /* Receive the waiting data. */
+ if(active_socket->tlshandle){
+ int isEncrypted;
+ tsk_size_t len = wsaBuffer.len;
+ if(!(ret = tnet_tls_socket_recv(active_socket->tlshandle, &wsaBuffer.buf, &len, &isEncrypted))){
+ if(isEncrypted){
+ TSK_FREE(wsaBuffer.buf);
+ goto done;
+ }
+ wsaBuffer.len = len;
+ }
+ }
+ else{
+ if(TNET_SOCKET_TYPE_IS_STREAM(transport->master->type)){
+ ret = WSARecv(active_socket->fd, &wsaBuffer, 1, &readCount, &flags, 0, 0);
+ }
+ else{
+ int len = sizeof(remote_addr);
+ ret = WSARecvFrom(active_socket->fd, &wsaBuffer, 1, &readCount, &flags,
+ (struct sockaddr*)&remote_addr, &len, 0, 0);
+ }
+ if(readCount < wsaBuffer.len){
+ wsaBuffer.len = readCount;
+ /* wsaBuffer.buf = tsk_realloc(wsaBuffer.buf, readCount); */
+ }
+ }
+
+ if(ret){
+ ret = WSAGetLastError();
+ if(ret == WSAEWOULDBLOCK){
+ TSK_DEBUG_WARN("WSAEWOULDBLOCK error for READ SSESSION");
+ }
+ else if(ret == WSAECONNRESET && TNET_SOCKET_TYPE_IS_DGRAM(transport->master->type)){
+ /* For DGRAM ==> The sent packet gernerated "ICMP Destination/Port unreachable" result. */
+ TSK_FREE(wsaBuffer.buf);
+ goto done; // ignore and retry.
+ }
+ else{
+ TSK_FREE(wsaBuffer.buf);
+
+ removeSocket(index, context);
+ TNET_PRINT_LAST_ERROR("WSARecv have failed.");
+ goto done;
+ }
+ }
+ else
+ {
+ tnet_transport_event_t* e = tnet_transport_event_create(event_data, transport->callback_data, active_socket->fd);
+ e->data = wsaBuffer.buf;
+ e->size = wsaBuffer.len;
+ e->remote_addr = remote_addr;
+
+ TSK_RUNNABLE_ENQUEUE_OBJECT_SAFE(TSK_RUNNABLE(transport), e);
+ }
+FD_READ_DONE:;
+ }
+
+
+
+
+ /*================== FD_WRITE ==================*/
+ if(networkEvents.lNetworkEvents & FD_WRITE)
+ {
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_WRITE", transport->description);
+
+ if(networkEvents.iErrorCode[FD_WRITE_BIT]){
+ TSK_RUNNABLE_ENQUEUE(transport, event_error, transport->callback_data, active_socket->fd);
+ TNET_PRINT_LAST_ERROR("WRITE FAILED.");
+ goto done;
+ }
+ }
+
+
+
+ /*================== FD_CLOSE ==================*/
+ if(networkEvents.lNetworkEvents & FD_CLOSE){
+ TSK_DEBUG_INFO("NETWORK EVENT FOR SERVER [%s] -- FD_CLOSE", transport->description);
+
+ TSK_RUNNABLE_ENQUEUE(transport, event_closed, transport->callback_data, active_socket->fd);
+ removeSocket(index, context);
+ }
+
+ /* http://msdn.microsoft.com/en-us/library/ms741690(VS.85).aspx
+
+ The proper way to reset the state of an event object used with the WSAEventSelect function
+ is to pass the handle of the event object to the WSAEnumNetworkEvents function in the hEventObject parameter.
+ This will reset the event object and adjust the status of active FD events on the socket in an atomic fashion.
+ */
+ /* WSAResetEvent(active_event); <== DO NOT USE (see above) */
+
+done:
+ /* unlock context */
+ tsk_safeobj_unlock(context);
+
+ } /* while(transport->running) */
+
+
+bail:
+
+
+ TSK_DEBUG_INFO("Stopped [%s] server with IP {%s} on port {%d}...", transport->description, transport->master->ip, transport->master->port);
+ return 0;
+}
+
+
+
+
+tsk_object_t* tnet_transport_context_create()
+{
+ return tsk_object_new(tnet_transport_context_def_t);
+}
+
+
+//=================================================================================================
+// Transport context object definition
+//
+static tsk_object_t* transport_context_ctor(tsk_object_t * self, va_list * app)
+{
+ transport_context_t *context = self;
+ if(context){
+ tsk_safeobj_init(context);
+ }
+ return self;
+}
+
+static tsk_object_t* transport_context_dtor(tsk_object_t * self)
+{
+ transport_context_t *context = self;
+ if(context){
+ while(context->count){
+ removeSocket(0, context);
+ }
+ tsk_safeobj_deinit(context);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_transport_context_def_s =
+{
+sizeof(transport_context_t),
+transport_context_ctor,
+transport_context_dtor,
+tsk_null,
+};
+const tsk_object_def_t *tnet_transport_context_def_t = &tnet_transport_context_def_s;
+#endif /* TNET_UNDER_WINDOWS */
+
diff --git a/tinyNET/src/tnet_types.h b/tinyNET/src/tnet_types.h
new file mode 100644
index 0000000..8d08c0c
--- /dev/null
+++ b/tinyNET/src/tnet_types.h
@@ -0,0 +1,111 @@
+/*
+* 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_types.h
+ * @brief ????.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TYPES_H
+#define TNET_TYPES_H
+
+#include "tinynet_config.h"
+
+#if TNET_UNDER_WINDOWS
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <iphlpapi.h>
+#else
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/select.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <fcntl.h>
+# include <sys/ioctl.h>
+# include <unistd.h>
+# include <net/if.h>
+# if HAVE_IFADDRS
+# include <ifaddrs.h>
+# endif
+# if TNET_HAVE_POLL
+# include <poll.h>
+# endif /* TNET_HAVE_POLL */
+#endif
+
+#if defined(TNET_HAVE_SCTP)
+#include <netinet/sctp.h>
+#endif
+
+#include "tsk_errno.h"
+#include "tsk_list.h"
+
+TNET_BEGIN_DECLS
+
+typedef int32_t tnet_fd_t;
+typedef uint16_t tnet_port_t;
+typedef int32_t tnet_family_t;
+typedef char tnet_host_t[NI_MAXHOST];
+typedef char tnet_ip_t[INET6_ADDRSTRLEN];
+
+typedef tsk_list_t tnet_interfaces_L_t; /**< List of @ref tnet_interface_t elements.*/
+typedef tsk_list_t tnet_addresses_L_t; /**< List of @ref tnet_address_t elements.*/
+
+#if TNET_UNDER_WINDOWS
+# define TNET_INVALID_SOCKET INVALID_SOCKET
+# define TNET_ERROR_WOULDBLOCK WSAEWOULDBLOCK
+# define TNET_ERROR_INPROGRESS WSAEINPROGRESS
+# define TNET_ERROR_CONNRESET WSAECONNRESET
+# define TNET_ERROR_INTR WSAEINTR
+# define TNET_ERROR_ISCONN WSAEISCONN
+# define TNET_ERROR_EAGAIN TNET_ERROR_WOULDBLOCK /* WinSock FIX */
+# if defined(_WIN32_WCE)
+# define tnet_gai_strerror(...) "FIXME"
+# else
+# define tnet_gai_strerror gai_strerrorA
+# endif
+#else
+# define TNET_INVALID_SOCKET -1
+# define TNET_ERROR_WOULDBLOCK EWOULDBLOCK
+# define TNET_ERROR_INPROGRESS EINPROGRESS
+# define TNET_ERROR_CONNRESET ECONNRESET
+# define TNET_ERROR_INTR EINTR
+# define TNET_ERROR_ISCONN EISCONN
+# define TNET_ERROR_EAGAIN EAGAIN
+# define tnet_gai_strerror gai_strerror
+#endif
+#define TNET_INVALID_FD TNET_INVALID_SOCKET
+
+#ifdef _WIN32_WCE
+typedef TCHAR tnet_error_t[512];
+#else
+typedef char tnet_error_t[512];
+#endif
+
+TNET_END_DECLS
+
+#endif /* TNET_TYPES_H */
+
+
diff --git a/tinyNET/src/tnet_utils.c b/tinyNET/src/tnet_utils.c
new file mode 100644
index 0000000..8f7338e
--- /dev/null
+++ b/tinyNET/src/tnet_utils.c
@@ -0,0 +1,1593 @@
+/*
+* 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_utils.c
+ * @brief Network utility functions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+
+#include "tnet_utils.h"
+
+#include "tsk_debug.h"
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "tnet_socket.h"
+#include "tnet_endianness.h"
+#include "dns/tnet_dns_resolvconf.h"
+
+#include <string.h>
+
+/**@defgroup tnet_utils_group Network utility functions.
+*/
+
+
+/**@ingroup tnet_utils_group
+* Creates new @ref tnet_interface_t object.
+*/
+tnet_interface_t* tnet_interface_create(const char* description, const void* mac_address, tsk_size_t mac_address_length)
+{
+ return tsk_object_new(tnet_interface_def_t, description, mac_address, mac_address_length);
+}
+
+/**@ingroup tnet_utils_group
+* Creates new @ref tnet_address_t object.
+*/
+tnet_address_t* tnet_address_create(const char* ip)
+{
+ return tsk_object_new(tnet_address_def_t, ip);
+}
+
+/**@ingroup tnet_utils_group
+ *
+ * Gets last network error description.
+ *
+ * @param [out] error The short description of the last network error.
+**/
+void tnet_getlasterror(tnet_error_t *error)
+{
+ int err = tnet_geterrno();
+ memset(*error, 0, sizeof(*error));
+
+#if TNET_UNDER_WINDOWS
+ {
+#ifdef _WIN32_WCE
+ FormatMessage
+#else
+ FormatMessageA
+#endif
+ (
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ tsk_null,
+ err,
+ 0,
+ *error,
+ sizeof(*error)-1,
+ tsk_null);
+ }
+#else
+ strerror_r(err, *error, sizeof(*error));
+ //sprintf(*error, "Network error (%d).", err);
+#endif
+}
+
+/**@ingroup tnet_utils_group
+* Gets last error number. Will call @a WSAGetLastError() on Windows and
+* errno on unix-like systems.
+* @retval Error number.
+*/
+int tnet_geterrno()
+{
+#if TNET_UNDER_WINDOWS
+ return WSAGetLastError();
+#else
+ return errno;
+#endif
+}
+
+
+/**@ingroup tnet_utils_group
+ * Gets the list of all network interfaces/adapters.
+ *
+ * @retval Network interfaces.
+**/
+tnet_interfaces_L_t* tnet_get_interfaces()
+{
+ tnet_interfaces_L_t * ifaces = tsk_list_create();
+
+#if TNET_UNDER_WINDOWS /*=== WINDOWS XP/VISTA/7/CE===*/
+
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+ PIP_ADAPTER_INFO pAdapterInfo = NULL;
+ PIP_ADAPTER_INFO pAdapter = NULL;
+ DWORD dwRetVal = 0;
+
+ ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
+ pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof (IP_ADAPTER_INFO));
+ if(pAdapterInfo == NULL)
+ {
+ TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
+ goto bail;
+ }
+ // Make an initial call to GetAdaptersInfo to get the necessary size into the ulOutBufLen variable
+ if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW)
+ {
+ FREE(pAdapterInfo);
+ pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(ulOutBufLen);
+ if(pAdapterInfo == NULL)
+ {
+ TSK_DEBUG_ERROR("Error allocating memory needed to call GetAdaptersinfo.");
+ goto bail;
+ }
+ }
+
+ if ((dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)) == NO_ERROR)
+ {
+ pAdapter = pAdapterInfo;
+ while(pAdapter)
+ {
+ tnet_interface_t *iface;
+
+ if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK){
+ continue;
+ }
+
+ iface = tnet_interface_create(pAdapter->Description, pAdapter->Address, pAdapter->AddressLength);
+ iface->index = pAdapter->Index;
+ tsk_list_push_back_data(ifaces, &(iface));
+
+ pAdapter = pAdapter->Next;
+ }
+ }
+
+ if(pAdapterInfo)
+ {
+ FREE(pAdapterInfo);
+ }
+
+
+#undef MALLOC
+#undef FREE
+
+
+#elif HAVE_IFADDRS /*=== Using getifaddrs ===*/
+
+ // see http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html
+ struct ifaddrs *ifaddr = tsk_null, *ifa = tsk_null;
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TSK_DEBUG_ERROR("getifaddrs failed and errno= [%d]", tnet_geterrno());
+ goto bail;
+ }
+
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ if(ifa->ifa_flags & IFF_LOOPBACK) {
+ continue;
+ }
+
+ if(ifa->ifa_addr->sa_family != AF_LINK){
+ continue;
+ }
+
+#if defined(__linux__)
+ {
+ struct ifreq ifr;
+ tnet_fd_t fd = TNET_INVALID_FD;
+
+ if((fd = socket(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
+ goto next;
+ }
+
+ ifr.ifr_addr.sa_family = ifa->ifa_addr->sa_family;
+ strcpy(ifr.ifr_name, ifa.ifa_name);
+ if(tnet_ioctl(fd, SIOCGIFHWADDR, &ifr)<0){
+ TSK_DEBUG_ERROR("tnet_ioctl(SIOCGIFHWADDR)", tnet_geterrno());
+ goto next;
+ }
+ else{
+ //sockaddr_dl* sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ tnet_interface_t *iface = tnet_interface_create(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ }
+ next:
+ tnet_sockfd_close(&fd);
+ }
+#else
+ {
+ //struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifa->ifa_addr;
+ tnet_interface_t *iface = tnet_interface_create(ifa->ifa_name, ifa->ifa_addr, 6);
+ iface->index = if_nametoindex(ifa->ifa_name);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ }
+#endif
+
+ }/* for */
+
+ freeifaddrs(ifaddr);
+
+#else /*=== ANDROID,... --> Using SIOCGIFCONF and SIOCGIFHWADDR ===*/
+
+ tnet_fd_t fd = TNET_INVALID_FD;
+ char buffer[1024];
+ struct ifconf ifc;
+
+ struct sockaddr_in *sin;
+ struct ifreq *ifr;
+
+ if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ TSK_DEBUG_ERROR("Failed to create new DGRAM socket and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+
+ ifc.ifc_len = sizeof(buffer);
+ ifc.ifc_buf = buffer;
+
+ if(ioctl(fd, SIOCGIFCONF, &ifc) < 0){
+ TSK_DEBUG_ERROR("ioctl(SIOCGIFCONF) failed and errno= [%d]", tnet_geterrno());
+ goto done;
+ }
+
+ for(ifr = ifc.ifc_req; ifr && !tsk_strempty(ifr->ifr_name); ifr++){
+ sin = (struct sockaddr_in *)&(ifr->ifr_addr);
+ // TODO: IPAddress if needed
+ if(/*ioctl(fd, SIOCGIFFLAGS, &ifr) == 0*/1){
+ if (!(ifr->ifr_flags & IFF_LOOPBACK)){
+ if(/*ioctl(fd, SIOCGIFHWADDR, &ifr) == 0*/1){
+ tnet_interface_t *iface = tnet_interface_create(ifr->ifr_name, ifr->ifr_hwaddr.sa_data, 6);
+ tsk_list_push_back_data(ifaces, (void**)&(iface));
+ //iface->index = if_nametoindex(ifr->ifr_name);
+ }
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("ioctl(SIOCGIFFLAGS) failed and errno= [%d]", tnet_geterrno());
+ }
+ }
+
+done:
+ tnet_sockfd_close(&fd);
+
+
+#endif
+
+bail:
+ return ifaces;
+}
+
+/**@ingroup tnet_utils_group
+* Get all IP addresses of the local machine.
+* @param family The @a family of the addresses to return.
+* @param unicast Indicates whether to return @a unicast addresses or not (1=yes and 0=no).
+* @param anycast Indicates whether to return @a anycast addresses or not (1=yes and 0=no).
+* @param multicast Indicates whether to return @a multicast addresses or not (1=yes and 0=no).
+* @param dnsserver Indicates whether to include dns servers or not (1=yes and 0=no).
+* @param if_index the index of the interface for which to to retrieve IP addresses.
+* -1 mean all interfaces.
+* @retval List of all addresses.
+*/
+tnet_addresses_L_t* tnet_get_addresses(tnet_family_t family, unsigned unicast, unsigned anycast, unsigned multicast, unsigned dnsserver, long if_index)
+{
+ tnet_addresses_L_t *addresses = tsk_list_create();
+
+#if TSK_UNDER_WINDOWS
+
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+ /* Declare and initialize variables */
+ tnet_ip_t ip;
+ DWORD dwSize = 0;
+ DWORD dwRetVal = 0;
+
+ int i = 0;
+
+ // Set the flags to pass to GetAdaptersAddresses
+ ULONG flags = GAA_FLAG_INCLUDE_PREFIX;
+
+ LPVOID lpMsgBuf = NULL;
+
+ PIP_ADAPTER_ADDRESSES pAddresses = NULL;
+ ULONG outBufLen = 0;
+
+ PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
+ PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;
+ PIP_ADAPTER_ANYCAST_ADDRESS pAnycast = NULL;
+ PIP_ADAPTER_MULTICAST_ADDRESS pMulticast = NULL;
+ IP_ADAPTER_DNS_SERVER_ADDRESS *pDnServer = NULL;
+ IP_ADAPTER_PREFIX *pPrefix = NULL;
+
+
+ outBufLen = sizeof(IP_ADAPTER_ADDRESSES);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
+
+ // Make an initial call to GetAdaptersAddresses to get the
+ // size needed into the outBufLen variable
+ if(GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen) == ERROR_BUFFER_OVERFLOW){
+ FREE(pAddresses);
+ pAddresses = (IP_ADAPTER_ADDRESSES *) MALLOC(outBufLen);
+ }
+ else goto bail;
+
+ if(pAddresses == NULL){
+ TSK_DEBUG_ERROR("Memory allocation failed for IP_ADAPTER_ADDRESSES struct.");
+ goto bail;
+ }
+
+ dwRetVal = GetAdaptersAddresses(family, flags, NULL, pAddresses, &outBufLen);
+
+ if(dwRetVal == NO_ERROR) {
+ pCurrAddresses = pAddresses;
+ while (pCurrAddresses){
+ if((if_index != -1) && (pCurrAddresses->IfIndex != if_index && pCurrAddresses->Ipv6IfIndex != if_index)){
+ goto next;
+ }
+
+ /* == UNICAST addresses == */
+ pUnicast = pCurrAddresses->FirstUnicastAddress;
+ while(unicast && pUnicast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pUnicast->Address.lpSockaddr, &ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pUnicast->Address.lpSockaddr->sa_family;
+ address->unicast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pUnicast = pUnicast->Next;
+ }
+
+ /* == ANYCAST addresses == */
+ pAnycast = pCurrAddresses->FirstAnycastAddress;
+ while(anycast && pAnycast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pAnycast->Address.lpSockaddr, &ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pAnycast->Address.lpSockaddr->sa_family;
+ address->anycast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pAnycast = pAnycast->Next;
+ }
+
+ /* == MULTYCAST addresses == */
+ pMulticast = pCurrAddresses->FirstMulticastAddress;
+ while(multicast && pMulticast){
+ //memset(ip, '\0', sizeof(ip));
+ tnet_get_sockip(pMulticast->Address.lpSockaddr, &ip);
+ {
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pMulticast->Address.lpSockaddr->sa_family;
+ address->multicast = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pMulticast = pMulticast->Next;
+ }
+
+ /* == DNS servers == */
+ pDnServer = pCurrAddresses->FirstDnsServerAddress;
+ while(dnsserver && pDnServer){
+ //memset(ip, '\0', sizeof(ip));
+ if(!tnet_get_sockip(pDnServer->Address.lpSockaddr, &ip)){
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = pDnServer->Address.lpSockaddr->sa_family;
+ address->dnsserver = 1;
+ tsk_list_push_ascending_data(addresses, &address);
+ }
+
+ pDnServer = pDnServer->Next;
+ }
+next:
+ pCurrAddresses = pCurrAddresses->Next;
+ }
+ }
+
+ if(pAddresses){
+ FREE(pAddresses);
+ }
+
+#undef MALLOC
+#undef FREE
+
+bail:
+
+#else /* !TSK_UNDER_WINDOWS (MAC OS X, UNIX, ANDROID ...) */
+
+#if HAVE_IFADDRS /*=== Using getifaddrs ===*/
+
+ // see http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html
+ struct ifaddrs *ifaddr = 0, *ifa = 0;
+ struct sockaddr *addr;
+ tnet_ip_t ip;
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TSK_DEBUG_ERROR("getifaddrs failed and errno= [%d]", tnet_geterrno());
+ goto bail;
+ }
+
+ /* == Unicast addresses == */
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ // Skip loopback
+ if (ifa->ifa_flags & IFF_LOOPBACK) {
+ continue;
+ }
+
+ // Skip unwanted interface
+ if (if_index != -1 && if_nametoindex(ifa->ifa_name) != if_index) {
+ continue;
+ }
+
+ // Only deal with Unicast address
+ if (unicast) {
+ if (family == AF_INET && ifa->ifa_addr->sa_family != AF_INET) {
+ continue;
+ }
+ if (family == AF_INET6 && ifa->ifa_addr->sa_family != AF_INET6) {
+ continue;
+ }
+ if (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6) {
+ continue;
+ }
+
+ // Get the IP string
+ addr = (struct sockaddr *) ifa->ifa_addr;
+ tnet_get_sockip(addr, &ip);
+
+ // Push a new address
+ tnet_address_t *address = tnet_address_create(ip);
+ address->family = ifa->ifa_addr->sa_family;
+ address->unicast = 1;
+ tsk_list_push_ascending_data(addresses, (void **) &address);
+ }
+ }
+
+ if (ifaddr) {
+ free(ifaddr);
+ }
+
+#endif /* HAVE_IFADDRS */
+
+bail:
+
+ /* == DNS servers == */
+ if(dnsserver){
+ tnet_addresses_L_t * dns_servers;
+ if((dns_servers = tnet_dns_resolvconf_parse("/etc/resolv.conf"))){
+ tsk_list_pushback_list(addresses, dns_servers);
+ TSK_OBJECT_SAFE_FREE(dns_servers);
+ }
+ }
+
+#endif
+
+ return addresses;
+}
+
+#if defined(__APPLE__)
+
+#include <net/if_dl.h>
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
+#include "net/route.h"
+#else
+#include <net/route.h>
+#endif
+
+#endif
+
+/**@ingroup tnet_utils_group
+* Retrieves the @a source IP address that has the best route to the specified IPv4 or IPv6 @a destination.
+* @param destination The destination address.
+* @param port The destination port.
+* @param type The socket type.
+* @param source The best @a source.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source)
+{
+ int ret = -1;
+ struct sockaddr_storage destAddr;
+
+#if TNET_UNDER_WINDOWS
+ long dwBestIfIndex = -1;
+#endif
+
+ if(!destination || !source){
+ TSK_DEBUG_ERROR("Invalid parameter");
+ goto bail;
+ }
+
+ if((ret = tnet_sockaddr_init(destination, port, type, &destAddr))){
+ goto bail;
+ }
+
+#if TNET_UNDER_WINDOWS /* Windows XP/Vista/7 and Windows Mobile */
+ if(GetBestInterfaceEx((struct sockaddr*)&destAddr, &dwBestIfIndex) != NO_ERROR){
+ ret = tnet_geterrno();
+ TNET_PRINT_LAST_ERROR("GetBestInterfaceEx() failed.");
+ goto bail;
+ }
+ else{
+ tnet_addresses_L_t* addresses = tsk_null;
+ const tsk_list_item_t* item;
+
+ if(!(addresses = tnet_get_addresses(TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET, tsk_true, tsk_false, tsk_false, tsk_false, dwBestIfIndex))){
+ ret = -2;
+ TSK_DEBUG_ERROR("Failed to retrieve addresses.");
+ goto bail;
+ }
+
+ tsk_list_foreach(item, addresses){
+ const tnet_address_t* address = item->data;
+ if(address && address->ip){
+ memset(*source, '\0', sizeof(*source));
+ memcpy(*source, address->ip, tsk_strlen(address->ip) > sizeof(*source) ? sizeof(*source) : tsk_strlen(address->ip));
+ ret = 0;
+ break; // First is good for us.
+ }
+ }
+ TSK_OBJECT_SAFE_FREE(addresses);
+ }
+#elif defined(__APPLE__) /* Mac OS X, iPhone, iPod Touch and iPad */
+ /* Thanks to Laurent Etiemble */
+
+ static int seq = 1234;
+ char buf[1024];
+ char *cp;
+ int s, i, l, rlen;
+ int pid = getpid();
+ u_long rtm_inits;
+ struct rt_metrics rt_metrics;
+ struct sockaddr_storage so_dst = destAddr;
+ struct sockaddr_dl so_ifp;
+ struct sockaddr *sa = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct ifaddrs *ifaddr = 0, *ifa = 0;
+ tnet_ip_t ip;
+
+ bzero(rtm, 1024);
+ cp = (char *)(rtm + 1);
+
+ so_ifp.sdl_index = 0;
+ so_ifp.sdl_family = AF_LINK;
+ so_ifp.sdl_len = sizeof(struct sockaddr_dl);
+
+ rtm->rtm_type = RTM_GET;
+ rtm->rtm_flags = RTF_STATIC | RTF_UP | RTF_GATEWAY;
+ rtm->rtm_version = RTM_VERSION;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_addrs = RTA_DST | RTA_IFP;
+ rtm->rtm_rmx = rt_metrics;
+ rtm->rtm_inits = rtm_inits;
+ rtm->rtm_index = 0;
+
+ /** Roundup value to a 4 bytes boundary. */
+#define ROUNDUP(a) \
+((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+
+ l = ROUNDUP(so_dst.ss_len);
+ memcpy(&so_dst, cp, l);
+ cp += l;
+
+ l = ROUNDUP(so_ifp.sdl_len);
+ memcpy(&so_ifp, cp, l);
+ cp += l;
+
+ l = cp - buf;
+ rtm->rtm_msglen = l;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ // TODO
+ }
+
+ if ((rlen = write(s, rtm, l)) < 0) {
+ printf("writing to routing socket");
+ // TODO
+ }
+ do {
+ l = read(s, rtm, 1024);
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+
+ /** Advance an address to the closest 4 bytes boundary. */
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+ if (rtm->rtm_errno == 0 && rtm->rtm_addrs) {
+ cp = (char *)(rtm + 1);
+ for (i = 1; i; i <<= 1) {
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+ case RTA_IFP:
+ ifp = (struct sockaddr_dl *) sa;
+ break;
+ }
+ ADVANCE(cp, sa);
+ }
+ }
+ }
+
+ if (ifp) {
+ printf(" interface: %.*s\n", ifp->sdl_nlen, ifp->sdl_data);
+
+ /* Get interfaces */
+ if(getifaddrs(&ifaddr) == -1){
+ TNET_PRINT_LAST_ERROR("getifaddrs() failed.");
+ goto bail;
+ }
+
+ for(ifa = ifaddr; ifa; ifa = ifa->ifa_next){
+ if (ifa->ifa_flags & IFF_LOOPBACK) {
+ continue;
+ }
+
+ if (if_nametoindex(ifa->ifa_name) != ifp->sdl_index) {
+ continue;
+ }
+
+ if (ifa->ifa_addr->sa_family != destAddr.ss_family) {
+ continue;
+ }
+
+ if (destAddr.ss_family == AF_INET6) {
+ if (IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr) ^
+ IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) &destAddr)->sin6_addr)) {
+ continue;
+ }
+ if (IN6_IS_ADDR_SITELOCAL(&((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr) ^
+ IN6_IS_ADDR_SITELOCAL(&((struct sockaddr_in6 *) &destAddr)->sin6_addr)) {
+ continue;
+ }
+ }
+
+ tnet_get_sockip((struct sockaddr *) ifa->ifa_addr, &ip);
+
+ memset(*source, '\0', sizeof(*source));
+ memcpy(*source, ip, tsk_strlen(ip) > sizeof(*source) ? sizeof(*source) : tsk_strlen(ip));
+ ret = 0;
+ goto bail; // First is good for us.
+ }
+ }
+
+#else /* All other systems (Google Android, Unix-Like systems, uLinux, ....) */
+
+
+#endif
+
+bail:
+ return ret;
+}
+
+
+/**@ingroup tnet_utils_group
+ *
+ * Converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures.
+ * You MUST call @ref tnet_freeaddrinfo() function to free the result.
+ *
+ * @param [in] node A pointer to a NULL-terminated ANSI string that contains a host (node) name or a numeric host address string. For the Internet protocol, the numeric host address string is a dotted-decimal IPv4 address or an IPv6 hex address..
+ * @param [in] service A pointer to a NULL-terminated ANSI string that contains either a service name or port number represented as a string.
+ * @param [in] hints A pointer to an addrinfo structure that provides hints about the type of socket the caller supports.
+ * @param [out] res A pointer to a linked list of one or more addrinfo structures that contains response information about the host.
+ *
+ * @retval Success returns zero. Failure returns a nonzero error code.
+**/
+int tnet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+ int ret = -1;
+ if(hints && (ret = getaddrinfo(node, service, hints, res))){
+ TSK_DEBUG_ERROR("getaddrinfo(family=%d, node=%s and service=%s) failed: [%s]", hints->ai_family, node, service, tnet_gai_strerror(ret));
+ }
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+ *
+ * This function frees address information previously allocated using @ref tnet_getaddrinfo.
+ *
+ * @param [in] ai The address information to free.
+**/
+void tnet_freeaddrinfo(struct addrinfo *ai)
+{
+ if(ai){
+ freeaddrinfo(ai);
+ }
+}
+
+/**@ingroup tnet_utils_group
+* Converts a descriptor to @b sockaddr_storage structure.
+* @param fd The descriptor to convert.
+* @param result @b sockaddr_storage structre representing the desciptor.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_get_sockaddr(tnet_fd_t fd, struct sockaddr_storage *result)
+{
+ if(fd >0){
+ socklen_t namelen = sizeof(*result);
+ return getsockname(fd, (struct sockaddr*)result, &namelen);
+ }
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+* Retrieves the socket type of a File Descriptor.
+* @param fd The File descriptor for which to retrive the type.
+* @retval @ref tnet_socket_type_t.
+*/
+tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd)
+{
+ tnet_socket_type_t type = tnet_socket_type_invalid;
+
+ /*if(fd >0)
+ {
+ struct sockaddr_storage ss;
+ if(!tnet_get_sockaddr(fd, &ss))
+ {
+ if(((struct sockaddr *)&ss)->sa_family == AF_INET)
+ {
+ TNET_SOCKET_TYPE_AS_IPV4(type);
+ }
+ else if(((struct sockaddr *)&ss)->sa_family == AF_INET6)
+ {
+ TNET_SOCKET_TYPE_AS_IPV6(type);
+ }
+ }
+ }*/
+
+ return type;
+}
+
+/**@ingroup tnet_utils_group
+* Gets the IP family of the @a host (e.g. "google.com" or "192.168.16.104" or "::1").
+* If the @a host is FQDN associated with both IPv4 and IPv6 then the result is unpredictable.
+* @param host The IP address or hostname for which to get the IP family.
+* @param port The port associated to the @a host. Will be used as the default service.
+* @retval @a AF_* if succeed and @a AF_UNSPEC otherwise.
+*/
+tnet_family_t tnet_get_family(const char* host, tnet_port_t port)
+{
+ tnet_family_t ret = AF_UNSPEC;
+ if(host){
+ int status;
+ tsk_istr_t srv;
+ struct addrinfo *result = tsk_null;
+ struct addrinfo hints;
+
+ /* set the port: used as the default service */
+ if(port){
+ tsk_itoa(port, &srv);
+ }
+ else{
+ memset(srv, '\0', sizeof(srv));
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+
+ if((status = tnet_getaddrinfo(host, srv, &hints, &result))){
+ TNET_PRINT_LAST_ERROR("getaddrinfo failed:");
+ goto done;
+ }
+
+ /* Get the First result. */
+ if(result){
+ ret = result->ai_family;
+ goto done;
+ }
+done:
+ freeaddrinfo(result);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+* Gets the IP address and the Port of a @b sockaddr object.
+* @param addr [in] A pointer to @b sockaddr structure for which to retrieve the IP address and port.
+* @param ip [out] The IP address.
+* @param port [out] The port.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_get_sockip_n_port(struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port)
+{
+ int status = -1;
+
+ if(addr->sa_family == AF_INET){
+ struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+ if(port){
+ *port = tnet_ntohs(sin->sin_port);
+ status = 0;
+ }
+ if(ip){
+ if((status = tnet_getnameinfo((struct sockaddr*)sin, sizeof(*sin), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST))){
+ return status;
+ }
+ }
+ }
+ else if(addr->sa_family == AF_INET6)
+ {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
+#if TNET_UNDER_WINDOWS
+ int index;
+#endif
+ if(port){
+ *port = tnet_ntohs(sin6->sin6_port);
+ status = 0;
+ }
+ if(ip){
+ if((status = tnet_getnameinfo((struct sockaddr*)sin6, sizeof(*sin6), *ip, sizeof(*ip), 0, 0, NI_NUMERICHOST))){
+ return status;
+ }
+
+#if TNET_UNDER_WINDOWS
+ if((index = tsk_strindexOf(*ip, tsk_strlen(*ip), "%")) > 0){
+ *(*ip + index) = '\0';
+ }
+#endif
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("Unsupported address family.");
+ return status;
+ }
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+* Gets the IP address and port of the remote peer.
+* <b>The socket MUST be connect()ed.</b>
+* @param localFD Local socket.
+* @param ip [out] The IP address of the remote peer.
+* @param port [out] The remote (peer) port.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_get_peerip_n_port(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if(port){
+ *port = 0;
+ }
+
+ if(localFD > 0){
+ int status;
+ socklen_t len;
+ struct sockaddr_storage ss;
+
+ len = sizeof(ss);
+ if((status = getpeername(localFD, (struct sockaddr *)&ss, &len))){
+ TSK_DEBUG_ERROR("TNET_GET_SOCKADDR has failed with status code: %d", status);
+ return -1;
+ }
+
+ return tnet_get_sockip_n_port(((struct sockaddr *)&ss), ip, port);
+ }
+
+ TSK_DEBUG_ERROR("Could not use an invalid socket description.");
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+* Gets the IP address and the Port of a local socket (File descriptor).
+* @param fd The decriptor for which to retrive the IP address and port.
+* @param ip [out] The IP address of the local socket.
+* @param port [out] The port of the local socket.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_get_ip_n_port(tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port)
+{
+ if(port){
+ *port = 0;
+ }
+
+ if(fd > 0){
+ int status;
+ struct sockaddr_storage ss;
+ if((status = tnet_get_sockaddr(fd, &ss))){
+ TSK_DEBUG_ERROR("TNET_GET_SOCKADDR has failed with status code: %d", status);
+ return -1;
+ }
+
+ return tnet_get_sockip_n_port(((struct sockaddr *)&ss), ip, port);
+ }
+
+ TSK_DEBUG_ERROR("Could not use an invalid socket description.");
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+* Provides protocol-independent name resolution from an address to an ANSI host name and from a port number to the ANSI service name.
+* @param sa A pointer to a socket address structure that contains the address and port number of the socket. For IPv4, the sa parameter points to a sockaddr_in structure. For IPv6, the sa parameter points to a @b sockaddr_in6 structure.
+* @param salen The length, in bytes, of the structure pointed to by the sa parameter.
+* @param node A pointer to an ANSI string used to hold the host name. On success, a pointer to the host name is returned as a Fully Qualified Domain Name (FQDN) by default. If the host parameter is NULL, this indicates the caller does not want to receive a host name string.
+* @param nodelen The length, in bytes, of the buffer pointed to by the host parameter. The caller must provide a buffer large enough to hold the host name, including the terminating NULL character.
+* @param service A pointer to an ANSI string to hold the service name. On success, a pointer is returned to an ANSI string that represents the service name associated with the port number. If the serv parameter is NULL, this indicates the caller does not want to receive a service name string.
+* @param servicelen The length, in bytes, of the buffer pointed to by the serv parameter. The caller must provide a buffer large enough to hold the service name, including the terminating NULL character.
+* @param flags A value used to customize processing of the @b getnameinfo function. See the Remarks section.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_getnameinfo(const struct sockaddr *sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags)
+{
+ return getnameinfo(sa, salen, node, nodelen, service, servicelen, flags);
+}
+
+/**@ingroup tnet_utils_group
+* Retrieves the standard host name for the local computer.
+* @param result A pointer to a buffer that receives the local host name.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_gethostname(tnet_host_t* result)
+{
+ return gethostname(*result, sizeof(*result));
+}
+
+/**@ingroup tnet_utils_group
+* Waits until the socket becomes writable/readable or @a timeout milliseconds passed.
+* This function could be used just after you have @a connect()ed a non-blocking socket.
+* @param fd The socket for which to check writability/readability.
+* @param timeout The number of milliseconds to wait. The function will immediately return if the socket
+* is already connected and writable/readable. Set the @a timeout value to -1 to wait indefinitely.
+* @param writable Indicates whether to wait for writability or readability.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockfd_waitUntil(tnet_fd_t fd, long timeout, tsk_bool_t writable)
+{
+ int ret = -1;
+ fd_set fds;
+ struct timeval timetowait;
+
+ if(fd<=0){
+ goto bail;
+ }
+
+ if(timeout >=0){
+ timetowait.tv_sec = (timeout/1000);
+ timetowait.tv_usec = (timeout%1000) * 1000;
+ }
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ ret = select(fd + 1, writable?0:&fds, writable?&fds:0, 0, (timeout >=0) ? &timetowait : 0);
+
+ if(ret == 0){ /* timedout */
+ ret = -2;
+ }
+ else if(ret == 1/* the total number of socket handles that are ready */){
+ ret = 0; // Ok
+ }
+ //else: error
+
+bail:
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+* NOT IMPLEMENTED.
+*/
+int tnet_sockfd_joingroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
+{
+ int ret = -1;
+ //struct ipv6_mreq mreq6;
+ //struct sockaddr_storage ss;
+
+ //if((ret = tnet_sockaddr_init(multiaddr, 0, tnet_socket_type_udp_ipv6, &ss)))
+ //{
+ // return ret;
+ //}
+
+ //memcpy(&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *) &ss)->sin6_addr, sizeof(struct in6_addr));
+ //mreq6.ipv6mr_interface = iface_index;
+
+ //if((ret = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (const char*)&mreq6, sizeof(mreq6))))
+ //{
+ // TNET_PRINT_LAST_ERROR("Failed to join IPv6 multicast group.");
+ // return ret;
+ //}
+
+ return ret;
+}
+/**@ingroup tnet_utils_group
+* NOT IMPLEMENTED.
+*/
+int tnet_sockfd_leavegroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index)
+{
+ //if(multiaddr)
+ {
+ }
+ return -1;
+}
+
+/**@ingroup tnet_utils_group
+* Converts human-readable text strings representing hostnames or IP addresses into a dynamically allocated linked list of struct addrinfo structures.
+*/
+int tnet_sockaddrinfo_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol)
+{
+ int status = 0;
+ struct addrinfo *result = 0;
+ struct addrinfo *ptr = 0;
+ struct addrinfo hints;
+ tsk_istr_t p;
+
+ tsk_itoa(port, &p);
+
+ /* hints address info structure */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(type) ? AF_INET6 : AF_INET);
+ hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(type) ? SOCK_STREAM : SOCK_DGRAM;
+ hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(type) ? IPPROTO_TCP : IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE;
+
+ /* Performs getaddrinfo */
+ if((status = tnet_getaddrinfo(host, p, &hints, &result))){
+ TNET_PRINT_LAST_ERROR("getaddrinfo have failed.");
+ goto bail;
+ }
+
+ /* Find our address. */
+ for(ptr = result; ptr; ptr = ptr->ai_next){
+ /* Only IPv4 and IPv6 are supported */
+ if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
+ continue;
+ }
+ /* duplicate addrinfo ==> Bad idea
+ *ai = tsk_calloc(1, sizeof (struct addrinfo));
+ memcpy (*ai, ptr, sizeof (struct addrinfo));
+ (*ai)->ai_addr = tsk_calloc(1, ptr->ai_addrlen);
+ memcpy((*ai)->ai_addr, ptr->ai_addr, ptr->ai_addrlen);
+ (*ai)->ai_addrlen = ptr->ai_addrlen;
+ (*ai)->ai_next = 0;
+ (*ai)->ai_canonname = 0;*/
+
+ if(ai_addr)memcpy(ai_addr, ptr->ai_addr, ptr->ai_addrlen);
+ if(ai_family) *ai_family = ptr->ai_family;
+ if(ai_socktype) *ai_socktype = ptr->ai_socktype;
+ if(ai_protocol) *ai_protocol = ptr->ai_protocol;
+
+ /* We prefer IPv4 but IPv6 can also work */
+ if(ptr->ai_family == AF_INET){
+ break;
+ }
+ }
+
+bail:
+ tnet_freeaddrinfo(result);
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+* Converts human-readable text strings representing hostnames or IP addresses into a @b sockaddr_storage structure.
+* @param host The hostname/IP address to convert.
+* @param port The local port associated to the host.
+* @param type The type of the socket to create.
+* @param addr [out] @b sockaddr_storage structure representing the @a host:port address.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockaddr_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr)
+{
+ int status;
+ struct sockaddr_storage ai_addr;
+
+ if((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, 0, 0, 0))){
+ return status;
+ }
+
+ memcpy(addr, &ai_addr, sizeof(ai_addr));
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+* Converts human-readable text strings representing hostnames or IP addresses as socket (File descriptor).
+* @param host The hostname/IP address to convert.
+* @param port The local port associated to the host.
+* @param type The type of the socket to create.
+* @param fd [out] The socket representing the @a host:port address.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockfd_init(const char *host, tnet_port_t port, enum tnet_socket_type_e type, tnet_fd_t *fd)
+{
+ int status = -1;
+ struct sockaddr_storage ai_addr;
+ int ai_family, ai_socktype, ai_protocol;
+ *fd = TNET_INVALID_SOCKET;
+
+ if((status = tnet_sockaddrinfo_init(host, port, type, &ai_addr, &ai_family, &ai_socktype, &ai_protocol))){
+ goto bail;
+ }
+
+ if((*fd = socket(ai_family, ai_socktype, ai_protocol)) == TNET_INVALID_SOCKET){
+ TNET_PRINT_LAST_ERROR("Failed to create new socket.");
+ goto bail;
+ }
+
+#if TNET_USE_POLL /* For win32 WSA* function the socket is auto. set to nonblocking mode. */
+ if((status = tnet_sockfd_set_nonblocking(*fd))){
+ goto bail;
+ }
+#endif
+
+#if TNET_HAVE_SS_LEN
+ if((status = bind(*fd, (const struct sockaddr*)&ai_addr, ai_addr.ss_len)))
+#else
+ if((status = bind(*fd, (const struct sockaddr*)&ai_addr, sizeof(ai_addr))))
+#endif
+ {
+ TNET_PRINT_LAST_ERROR("bind have failed.");
+ tnet_sockfd_close(fd);
+
+ goto bail;
+ }
+
+bail:
+ return (*fd == TNET_INVALID_SOCKET) ? status : 0;
+}
+
+/**@ingroup tnet_utils_group
+* Changes the blocking mode of the socket.
+* @param fd The socket for which to change to mode.
+* @param nonBlocking The new mode (0 =blocking and 1=non-blocking).
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking)
+{
+ if(fd != TNET_INVALID_FD)
+ {
+#if TNET_UNDER_WINDOWS
+ ULONG mode = nonBlocking;
+ if(ioctlsocket(fd, FIONBIO, &mode))
+ //if(WSAIoctl(fd, FIONBIO, &nonblocking, sizeof(nonblocking), NULL, 0, NULL, NULL, NULL) == SOCKET_ERROR)
+ {
+ TNET_PRINT_LAST_ERROR("ioctlsocket(FIONBIO) have failed.");
+ return -1;
+ }
+#else
+ int flags;
+ if((flags = fcntl(fd, F_GETFL, 0)) < 0) {
+ TNET_PRINT_LAST_ERROR("fcntl(F_GETFL) have failed.");
+ return -1;
+ }
+ if(fcntl(fd, F_SETFL, flags | (nonBlocking ? O_NONBLOCK : ~O_NONBLOCK)) < 0){
+ TNET_PRINT_LAST_ERROR("fcntl(O_NONBLOCK/O_NONBLOCK) have failed.");
+ return -1;
+ }
+#endif
+
+ // int on = 1;
+ // ioctl(fd, FIONBIO, (char *)&on);
+
+ }
+ return 0;
+}
+
+tnet_tls_socket_handle_t* tnet_sockfd_set_tlsfiles(tnet_fd_t fd, int isClient, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk)
+{
+ tnet_tls_socket_handle_t* tlshandle = 0;
+ if(fd == TNET_INVALID_FD){
+ return 0;
+ }
+
+ if(isClient){
+ tlshandle = tnet_tls_socket_client_create(fd, tlsfile_ca, tlsfile_pvk, tlsfile_pbk);
+ }
+ else{
+ tlshandle = tnet_tls_socket_server_create(fd, tlsfile_ca, tlsfile_pvk, tlsfile_pbk);
+ }
+
+ if(tnet_tls_socket_isok(tlshandle)){
+ return tlshandle;
+ }
+ else{
+ TSK_OBJECT_SAFE_FREE(tlshandle);
+ return 0;
+ }
+}
+
+/**@ingroup tnet_utils_group
+* Sends data to a specific destination.
+* @param fd The source socket.
+* @param to The destination socket.
+* @param buf A pointer to the buffer to send over the network.
+* @param size The size of the buffer.
+* @retval If no error occurs, sendto returns the total number of bytes sent, which can be less than the number indicated by @b size.
+* Otherwise, non-zero (negative) error code is returned.
+*/
+int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size)
+{
+ tsk_size_t sent = 0;
+ int ret = -1;
+
+ if(fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to send data.");
+ goto bail;
+ }
+ if(!buf || !size){
+ TSK_DEBUG_ERROR("Using invalid BUFFER.");
+ ret = -2;
+ goto bail;
+ }
+
+ while(sent < size){
+#if TNET_UNDER_WINDOWS
+ WSABUF wsaBuffer;
+ DWORD numberOfBytesSent = 0;
+ wsaBuffer.buf = ((CHAR*)buf) + sent;
+ wsaBuffer.len = (size-sent);
+ ret = WSASendTo(fd, &wsaBuffer, 1, &numberOfBytesSent, 0, to, tnet_get_sockaddr_size(to), 0, 0);
+#else
+ ret = sendto(fd, (((const uint8_t*)buf)+sent), (size-sent), 0, to, tnet_get_sockaddr_size(to));
+#endif
+ if(ret <= 0){
+ goto bail;
+ }
+ else{
+ sent += ret;
+ }
+ }
+
+bail:
+ return (size == sent) ? sent : ret;
+}
+
+/**@ingroup tnet_utils_group
+* Receives a datagram and stores the source address.
+* @param fd A descriptor identifying a bound socket.
+* @param buf A buffer for the incoming data.
+* @param size The length, in bytes, of the buffer pointed to by the buf parameter.
+* @param flags A set of options that modify the behavior of the function call beyond the options specified for the associated socket.
+* All flags which can be passed to @b recvfrom.
+* @param from An optional pointer to a buffer in a @b sockaddr structure that will hold the source address upon return.
+* If no error occurs, recvfrom returns the number of bytes received. If the connection has been gracefully closed, the return value is zero.
+* Otherwise, non-zero (negative) error code is returned.
+*/
+int tnet_sockfd_recvfrom(tnet_fd_t fd, void* buf, tsk_size_t size, int flags, struct sockaddr *from)
+{
+ socklen_t fromlen;
+
+ if(fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to recv data.");
+ return -1;
+ }
+
+#if TNET_HAVE_SA_LEN
+ fromlen = from->sa_len;
+#else
+ fromlen = sizeof(*from);
+#endif
+
+ return recvfrom(fd, buf, size, flags, from, &fromlen);
+}
+
+/**@ingroup tnet_utils_group
+* Sends data on a connected socket.
+* @param fd A descriptor identifying a connected socket.
+* @param buf A pointer to a buffer containing the data to be transmitted.
+* @param size The length, in bytes, of the data in buffer pointed to by the buf parameter.
+* @param flags A set of flags that specify the way in which the call is made.
+* All flags which can be passed to @b recv.
+* @retval If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the @b size parameter.
+*/
+tsk_size_t tnet_sockfd_send(tnet_fd_t fd, const void* buf, tsk_size_t size, int flags)
+{
+ int ret = -1;
+ tsk_size_t sent = 0;
+
+ if(fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to send data.");
+ goto bail;
+ }
+
+ while(sent < size){
+ if((ret = send(fd, (((const uint8_t*)buf)+sent), (size-sent), flags)) <= 0){
+ if(tnet_geterrno() == TNET_ERROR_WOULDBLOCK){
+ // FIXME: HORRIBLE HACK
+ if((ret = tnet_sockfd_waitUntilWritable(fd, TNET_CONNECT_TIMEOUT))){
+ break;
+ }
+ else continue;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("send failed.");
+ // Under Windows XP if WSAGetLastError()==WSAEINTR then try to disable both the ICS and the Firewall
+ // More info about How to disable the ISC: http://support.microsoft.com/?scid=kb%3Ben-us%3B230112&x=6&y=11
+ goto bail;
+ }
+ }
+ else{
+ sent += ret;
+ }
+ }
+
+bail:
+ //return (size == sent) ? sent : ret;
+ return sent;
+}
+
+/**@ingroup tnet_utils_group
+* Receives data from a connected socket or a bound connectionless socket.
+* @param fd The descriptor that identifies a connected socket.
+* @param buf A pointer to the buffer to receive the incoming data.
+* @param size The length, in bytes, of the buffer pointed to by the buf parameter.
+* @param flags A set of flags that influences the behavior of this function.
+* All flags which can be passed to @b recv.
+* @retval If no error occurs, recv returns the number of bytes received and the buffer pointed to by the buf parameter will contain this data received. If the connection has been gracefully closed, the return value is zero.
+* Otherwise, non-zero (negative) error code is returned.
+*/
+int tnet_sockfd_recv(tnet_fd_t fd, void* buf, tsk_size_t size, int flags)
+{
+ int ret = -1;
+
+ if(fd == TNET_INVALID_FD){
+ TSK_DEBUG_ERROR("Using invalid FD to recv data.");
+ goto bail;
+ }
+
+ if((ret = recv(fd, buf, size, flags)) <= 0){
+ TNET_PRINT_LAST_ERROR("recv failed.");
+ goto bail;
+ }
+
+bail:
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+* Establishes a connection to a specified socket.
+* @param fd A descriptor identifying an unconnected socket.
+* @param to A pointer to the @b sockaddr_storage structure to which the connection should be established.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockfd_connectto(tnet_fd_t fd, const struct sockaddr_storage *to)
+{
+ int status = -1;
+
+#if TNET_UNDER_WINDOWS
+
+ if((status = WSAConnect(fd, (LPSOCKADDR)to, sizeof(*to), NULL, NULL, NULL, NULL)) == SOCKET_ERROR){
+ status = WSAGetLastError();
+ if(status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_ISCONN || status == TNET_ERROR_INTR || status == TNET_ERROR_INPROGRESS){
+ TSK_DEBUG_WARN("TNET_ERROR_WOULDBLOCK/TNET_ERROR_ISCONN/TNET_ERROR_INTR/TNET_ERROR_INPROGRESS ==> use tnet_sockfd_waitUntilWritable.");
+ status = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("WSAConnect have failed.");
+ }
+ }
+
+#else /* !TNET_UNDER_WINDOWS */
+
+#if TNET_HAVE_SS_LEN
+ if((status = connect(fd, (struct sockaddr*)to, to->ss_len)))
+# else
+ if((status = connect(fd, (struct sockaddr*)to, sizeof(*to))))
+# endif
+ {
+ status = tnet_geterrno();
+ if(status == TNET_ERROR_WOULDBLOCK || status == TNET_ERROR_ISCONN || status == TNET_ERROR_INPROGRESS || status == TNET_ERROR_EAGAIN){
+ TSK_DEBUG_WARN("TNET_ERROR_WOULDBLOCK/TNET_ERROR_ISCONN/TNET_ERROR_INPROGRESS/TNET_ERROR_EAGAIN ==> use tnet_sockfd_waitUntilWritable.");
+ status = 0;
+ }
+ else{
+ TNET_PRINT_LAST_ERROR("connect have failed.");
+ }
+ }
+
+#endif /* TNET_UNDER_WINDOWS */
+
+ return status;
+}
+
+/**@ingroup tnet_utils_group
+*/
+int tnet_sockfd_listen(tnet_fd_t fd, int backlog)
+{
+ if(fd>0){
+ return listen(fd, backlog);
+ }
+ else return -1;
+}
+
+/**@ingroup tnet_utils_group
+*/
+tnet_fd_t tnet_sockfd_accept(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen)
+{
+ tnet_fd_t ret = TNET_INVALID_FD;
+
+ if(fd>0){
+ ret = accept(fd, addr, addrlen);
+ }
+
+ return ret;
+}
+
+/**@ingroup tnet_utils_group
+* Closes an existing socket.
+* @param fd A descriptor identifying the socket to close.
+* @retval Zero if succeed and non-zero error code otherwise.
+*/
+int tnet_sockfd_close(tnet_fd_t *fd)
+{
+ int ret;
+#if TNET_UNDER_WINDOWS
+ ret = closesocket(*fd);
+#else
+ ret = close(*fd);
+#endif
+
+ *fd = TNET_INVALID_FD;
+ return ret;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// INTERFACE object definition
+//
+static tsk_object_t* tnet_interface_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_interface_t *iface = self;
+ if(iface){
+ const char* description = va_arg(*app, const char*);
+ const void* mac_address = va_arg(*app, const void*);
+ tsk_size_t mac_address_length = va_arg(*app, tsk_size_t);
+
+ iface->description = tsk_strdup(description);
+ if((iface->mac_address = tsk_calloc(mac_address_length, sizeof(uint8_t)))){
+ memcpy(iface->mac_address, mac_address, mac_address_length);
+ }
+ iface->mac_address_length = mac_address_length;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_interface_dtor(tsk_object_t * self)
+{
+ tnet_interface_t *iface = self;
+ if(iface){
+ TSK_FREE(iface->description);
+ TSK_FREE(iface->mac_address);
+ }
+
+ return self;
+}
+
+static int tnet_interface_cmp(const tsk_object_t *if1, const tsk_object_t *if2)
+{
+ const tnet_interface_t *iface1 = if1;
+ const tnet_interface_t *iface2 = if2;
+
+ if(iface1 && iface2){
+ return tsk_stricmp(iface1->description, iface1->description);
+ }
+ else if(!iface1 && !iface2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tnet_interface_def_s =
+{
+ sizeof(tnet_interface_t),
+ tnet_interface_ctor,
+ tnet_interface_dtor,
+ tnet_interface_cmp,
+};
+const tsk_object_def_t *tnet_interface_def_t = &tnet_interface_def_s;
+
+
+
+
+//=================================================================================================
+// ADDRESS object definition
+//
+static tsk_object_t* tnet_address_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_address_t *address = self;
+ if(address){
+ address->ip = tsk_strdup(va_arg(*app, const char*));
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_address_dtor(tsk_object_t * self)
+{
+ tnet_address_t *address = self;
+ if(address){
+ TSK_FREE(address->ip);
+ }
+
+ return self;
+}
+
+static int tnet_address_cmp(const tsk_object_t *_a1, const tsk_object_t *_a2)
+{
+ const tnet_address_t *a1 = _a1;
+ const tnet_address_t *a2 = _a2;
+
+ if(a1 && a2){
+ // to have AF_UNSPEC, AF_UNIX, AF_INET, ... first
+ return (a1->family - a2->family);
+ }
+ else if(!a1 && !a2) return 0;
+ else return -1;
+}
+
+static const tsk_object_def_t tnet_address_def_s =
+{
+ sizeof(tnet_address_t),
+ tnet_address_ctor,
+ tnet_address_dtor,
+ tnet_address_cmp,
+};
+const tsk_object_def_t *tnet_address_def_t = &tnet_address_def_s;
+
diff --git a/tinyNET/src/tnet_utils.h b/tinyNET/src/tnet_utils.h
new file mode 100644
index 0000000..f9b02ae
--- /dev/null
+++ b/tinyNET/src/tnet_utils.h
@@ -0,0 +1,176 @@
+/*
+* 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_utils.h
+ * @brief Network utility functions.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_UTILS_H
+#define TNET_UTILS_H
+
+#include "tinynet_config.h"
+
+#include "tnet_socket.h"
+#include "tnet_types.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_utils_group
+*/
+#define TNET_CONNECT_TIMEOUT 2000
+
+/**Interface.
+*/
+typedef struct tnet_interface_s
+{
+ TSK_DECLARE_OBJECT;
+
+ unsigned index;
+
+ char* description;
+ uint8_t* mac_address;
+ tsk_size_t mac_address_length;
+}
+tnet_interface_t;
+
+
+/**Address.
+*/
+typedef struct tnet_address_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_family_t family;
+
+ unsigned unicast:1;
+ unsigned anycast:1;
+ unsigned multicast:1;
+ unsigned dnsserver:1;
+
+ char* ip;
+}
+tnet_address_t;
+
+TINYNET_API void tnet_getlasterror(tnet_error_t *error);
+TINYNET_API int tnet_geterrno();
+
+TINYNET_API tnet_interfaces_L_t* tnet_get_interfaces();
+TINYNET_API tnet_addresses_L_t* tnet_get_addresses(tnet_family_t family, unsigned unicast, unsigned anycast, unsigned multicast, unsigned dnsserver, long if_index);
+#define tnet_get_addresses_all() tnet_get_addresses(AF_UNSPEC, 1, 1, 1, 1, -1)
+#define tnet_get_addresses_all_unicast() tnet_get_addresses(AF_UNSPEC, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_unicast4() tnet_get_addresses(AF_INET, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_unicast6() tnet_get_addresses(AF_INET6, 1, 0, 0, 0, -1)
+#define tnet_get_addresses_all_anycast() tnet_get_addresses(AF_UNSPEC, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_anycast4() tnet_get_addresses(AF_INET, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_anycast6() tnet_get_addresses(AF_INET6, 0, 1, 0, 0, -1)
+#define tnet_get_addresses_all_multicast() tnet_get_addresses(AF_UNSPEC, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_multicast4() tnet_get_addresses(AF_INET, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_multicast6() tnet_get_addresses(AF_INET6, 0, 0, 1, 0, -1)
+#define tnet_get_addresses_all_dnsservers() tnet_get_addresses(AF_UNSPEC, 0, 0, 0, 1, -1)
+#define tnet_get_addresses_dnsservers4() tnet_get_addresses(AF_INET, 0, 0, 0, 1, -1)
+#define tnet_get_addresses_dnsservers6() tnet_get_addresses(AF_INET6, 0, 0, 0, 1, -1)
+
+TINYNET_API int tnet_getbestsource(const char* destination, tnet_port_t port, tnet_socket_type_t type, tnet_ip_t *source);
+TINYNET_API int tnet_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+TINYNET_API void tnet_freeaddrinfo(struct addrinfo *ai);
+TINYNET_API int tnet_get_sockaddr(tnet_fd_t fd, struct sockaddr_storage *result);
+TINYNET_API tnet_socket_type_t tnet_get_socket_type(tnet_fd_t fd);
+TINYNET_API tnet_family_t tnet_get_family(const char* host, tnet_port_t port);
+TINYNET_API int tnet_get_ip_n_port(tnet_fd_t fd, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_get_sockip_n_port(struct sockaddr *addr, tnet_ip_t *ip, tnet_port_t *port);
+TINYNET_API int tnet_get_peerip_n_port(tnet_fd_t localFD, tnet_ip_t *ip, tnet_port_t *port);
+#define tnet_get_ip(fd, ip) tnet_get_ip_n_port(fd, ip, 0)
+#define tnet_get_port(fd, port) tnet_get_ip_n_port(fd, 0, port)
+#define tnet_get_sockip(addr, ip) tnet_get_sockip_n_port(addr, ip, 0)
+#define tnet_get_sockport(addr, port) tnet_get_sockip_n_port(addr, 0, port)
+#define tnet_get_peerip(localFD, ip) tnet_get_peerip_n_port(localFD, ip, 0)
+#define tnet_get_peerport(localFD, port) tnet_get_peerip_n_port(localFD, 0, port)
+
+#if TNET_HAVE_SA_LEN
+# define tnet_get_sockaddr_size(psockaddr) (psockaddr)->sa_len
+#else
+# define tnet_get_sockaddr_size(psockaddr) ((psockaddr)->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6): ((psockaddr)->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(*(psockaddr))))
+#endif
+
+TINYNET_API int tnet_getnameinfo(const struct sockaddr *sa, socklen_t salen, char* node, socklen_t nodelen, char* service, socklen_t servicelen, int flags);
+TINYNET_API int tnet_gethostname(tnet_host_t* result);
+
+TINYNET_API int tnet_sockfd_waitUntil(tnet_fd_t fd, long timeout, tsk_bool_t writable);
+#define tnet_sockfd_waitUntilWritable(fd, timeout) tnet_sockfd_waitUntil(fd, timeout, tsk_true)
+#define tnet_sockfd_waitUntilReadable(fd, timeout) tnet_sockfd_waitUntil(fd, timeout, tsk_false)
+TINYNET_API int tnet_sockfd_joingroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index);
+TINYNET_API int tnet_sockfd_leavegroup6(tnet_fd_t fd, const char* multiaddr, unsigned iface_index);
+
+TINYNET_API int tnet_sockaddrinfo_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *ai_addr, int *ai_family, int *ai_socktype, int *ai_protocol);
+TINYNET_API int tnet_sockaddr_init(const char *host, tnet_port_t port, tnet_socket_type_t type, struct sockaddr_storage *addr);
+TINYNET_API int tnet_sockfd_init(const char *host, tnet_port_t port, tnet_socket_type_t type, tnet_fd_t *fd);
+
+TINYNET_API int tnet_sockfd_set_mode(tnet_fd_t fd, int nonBlocking);
+#define tnet_sockfd_set_nonblocking(fd) tnet_sockfd_set_mode(fd, 1)
+#define tnet_sockfd_set_blocking(fd) tnet_sockfd_set_mode(fd, 0)
+
+TINYNET_API tnet_tls_socket_handle_t* tnet_sockfd_set_tlsfiles(tnet_fd_t fd, int isClient, const char* tlsfile_ca, const char* tlsfile_pvk, const char* tlsfile_pbk);
+
+TINYNET_API int tnet_sockfd_sendto(tnet_fd_t fd, const struct sockaddr *to, const void* buf, tsk_size_t size);
+TINYNET_API int tnet_sockfd_recvfrom(tnet_fd_t fd, void* buf, tsk_size_t size, int flags, struct sockaddr *from);
+TINYNET_API tsk_size_t tnet_sockfd_send(tnet_fd_t fd, const void* buf, tsk_size_t size, int flags);
+TINYNET_API int tnet_sockfd_recv(tnet_fd_t fd, void* buf, tsk_size_t size, int flags);
+TINYNET_API int tnet_sockfd_connectto(tnet_fd_t fd, const struct sockaddr_storage *to);
+TINYNET_API int tnet_sockfd_listen(tnet_fd_t fd, int backlog);
+TINYNET_API tnet_fd_t tnet_sockfd_accept(tnet_fd_t fd, struct sockaddr *addr, socklen_t *addrlen);
+
+
+
+TINYNET_API int tnet_sockfd_close(tnet_fd_t *fd);
+
+/**Prints last network error to @b stderr.
+*/
+#define TNET_PRINT_LAST_ERROR(FMT, ...) \
+ { \
+ tnet_error_t error; \
+ tnet_getlasterror(&error); \
+ TSK_DEBUG_ERROR(FMT, ##__VA_ARGS__); \
+ TSK_DEBUG_ERROR("(SYSTEM)NETWORK ERROR ==>%s", error) \
+ }
+
+
+#if TSK_UNDER_WINDOWS
+# define tnet_ioctlt ioctlsocket /* FIXME: use WSAIoctl */
+#else
+# define tnet_ioctlt ioctl
+#endif
+
+
+tnet_interface_t* tnet_interface_create(const char* description, const void* mac_address, tsk_size_t mac_address_length);
+tnet_address_t* tnet_address_create(const char* ip);
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_interface_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_address_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_UTILS_H */
+
+
diff --git a/tinyNET/src/turn/tnet_turn.c b/tinyNET/src/turn/tnet_turn.c
new file mode 100644
index 0000000..08adb13
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.c
@@ -0,0 +1,700 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn.c
+ * @brief Traversal Using Relays around NAT (TURN) implementation as per 'draft-ietf-behave-turn-16', 'draft-ietf-behave-turn-tcp-05'
+ * and 'draft-ietf-behave-turn-ipv6'.
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-16
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-tcp-05
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-ipv6-07
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_turn.h"
+
+#include "tnet_turn_message.h"
+
+#include "tsk_string.h"
+#include "tsk_memory.h"
+
+#include "../tnet_nat.h"
+#include "../tnet_utils.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_md5.h"
+#include "tsk_debug.h"
+
+#include <string.h>
+
+/**@defgroup tnet_turn_group TURN(draft-ietf-behave-turn-16) implementation.
+*/
+
+/**@ingroup tnet_turn_group
+*/
+tnet_turn_channel_binding_t* tnet_turn_channel_binding_create(const tnet_turn_allocation_t *allocation)
+{
+ return tsk_object_new(tnet_turn_channel_binding_def_t, allocation);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_turn_permission_t* tnet_turn_permission_create(uint32_t timeout)
+{
+ return tsk_object_new(tnet_turn_permission_def_t, timeout);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_turn_allocation_t* tnet_turn_allocation_create(tnet_fd_t fd, tnet_socket_type_t socket_type, const char* server_address, tnet_port_t server_port, const char* username, const char* password)
+{
+ return tsk_object_new(tnet_turn_allocation_def_t, fd, socket_type, server_address, server_port, username, password);
+}
+
+/*
+- IMPORTANT: 16. Detailed Example
+- It is suggested that the client refresh the allocation roughly 1 minute before it expires.
+- If the client wishes to immediately delete an existing allocation, it includes a LIFETIME attribute with a value of 0.
+*/
+
+typedef tnet_stun_request_t* (*tnet_turn_create_request_func)(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app);
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_stun_message_type_t type)
+{
+ tnet_stun_attribute_t* attribute;
+ tnet_stun_request_t *request = tnet_stun_message_create(context->username, context->password);
+
+ if(request){
+ request->type = type;
+
+ request->fingerprint = context->enable_fingerprint;
+ request->integrity = context->enable_integrity;
+ request->dontfrag = context->enable_dontfrag;
+ request->realm = tsk_strdup(allocation->realm);
+ request->nonce = tsk_strdup(allocation->nonce);
+
+ /* Create random transaction id */
+ {
+ tsk_istr_t random;
+ tsk_md5digest_t digest;
+
+ tsk_strrandom(&random);
+ TSK_MD5_DIGEST_CALC(random, sizeof(random), digest);
+
+ memcpy(request->transaction_id, digest, TNET_STUN_TRANSACID_SIZE);
+ }
+
+ /* Add software attribute */
+ if(allocation->software){
+ attribute = (tnet_stun_attribute_t*)tnet_stun_attribute_software_create(allocation->software, tsk_strlen(allocation->software));
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+ }
+
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_allocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t* request = tnet_turn_create_request(context, allocation, stun_allocate_request);
+ if(request){
+ tnet_stun_attribute_t* attribute;
+
+ /* Add Requested transport. */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_reqtrans_create(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type) ? TNET_PROTO_UDP: TNET_PROTO_TCP))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+
+ /* Add lifetime */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_lifetime_create(tnet_ntohl(allocation->timeout)))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+
+ /* Add Event Port */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_even_port_create(context->enable_evenport))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+ }
+
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t *request = tnet_turn_create_request_allocate(context, allocation, app);
+ if(request){
+ request->type = stun_refresh_request;
+ }
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_unallocate(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t *request = tnet_turn_create_request_refresh(context, allocation, app);
+ if(request){
+ ((tnet_turn_attribute_lifetime_t*)tnet_stun_message_get_attribute(request, stun_lifetime))->value = 0;
+ }
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_channel_bind(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t* request = tnet_turn_create_request(context, allocation, stun_channelbind_request);
+ if(request){
+ const tnet_turn_channel_binding_t* channel_binding;
+ tnet_turn_attribute_t *attribute;
+ tnet_turn_channel_binding_id_t number;
+ uint32_t lifetime;
+
+
+ channel_binding = va_arg(*app, const tnet_turn_channel_binding_t *);
+ number = tnet_htons(channel_binding->id);
+ lifetime = tnet_htonl(channel_binding->timeout);
+ attribute = tsk_object_ref(channel_binding->xpeer);
+
+ /* XOR-PEER */
+ tnet_stun_message_add_attribute(request, &attribute);
+
+ /* CHANNEL-NUMBER */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_channelnum_create(number))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+
+ /* LIFETIME */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_lifetime_create(lifetime))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+ }
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_channel_refresh(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ return tnet_turn_create_request_channel_bind(context, allocation, app);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_sendindication(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t* request = tnet_turn_create_request(context, allocation, stun_send_indication);
+ if(request){
+ tnet_turn_attribute_t *attribute;
+ tnet_turn_attribute_xpeer_addr_t* xpeer = tsk_object_ref(va_arg(*app, tnet_turn_attribute_xpeer_addr_t *));
+ const void* data = va_arg(*app, const void *);
+ tsk_size_t size = va_arg(*app, tsk_size_t);
+
+ /*
+ draft-ietf-behave-turn-16 - 10.1. Forming a Send Indication
+
+ When forming a Send indication, the client MUST include a XOR-PEER-
+ ADDRESS attribute and a DATA attribute. The XOR-PEER-ADDRESS
+ attribute contains the transport address of the peer to which the
+ data is to be sent, and the DATA attribute contains the actual
+ application data to be sent to the peer.
+ */
+
+ /* XOR-PEER-ADDRESS */
+ tnet_stun_message_add_attribute(request, (tnet_turn_attribute_t**)&xpeer);
+
+ /* DATA */
+ if((attribute = (tnet_stun_attribute_t*)tnet_turn_attribute_data_create(data, size))){
+ tnet_stun_message_add_attribute(request, &attribute);
+ }
+ }
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_request_t* tnet_turn_create_request_permission(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, va_list *app)
+{
+ tnet_stun_request_t* request = tnet_turn_create_request(context, allocation, stun_createpermission_request);
+ if(request){
+ //--const char* ipaddress = va_arg(*app, const char *);
+
+ /* XOR-PEER-ADDRESS */
+ tnet_turn_attribute_xpeer_addr_t* attribute = tnet_turn_attribute_xpeer_addr_create_null();
+ attribute->family = stun_ipv4;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+
+ attribute->xaddress[0] = 0x79;
+ attribute->xaddress[1] = 0xA1;
+ attribute->xaddress[2] = 0x83;
+ attribute->xaddress[3] = 0x47;
+
+ tnet_stun_message_add_attribute(request, (tnet_stun_attribute_t**)&attribute);
+
+ /*if((attribute = tnet_turn_attribute_even_port_create(context->enable_evenport)))
+ {
+ tnet_stun_message_add_attribute(request, &attribute);
+ }*/
+ }
+ return request;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_send_request(const tnet_nat_context_t* context, tnet_turn_allocation_t* allocation, tnet_turn_create_request_func funcptr, ...)
+{
+ tnet_stun_request_t *request;
+ int ret = -1;
+ va_list ap;
+
+ va_start(ap, funcptr);
+ request = funcptr(context, allocation, &ap);
+ va_end(ap);
+
+ if(request){
+ if(TNET_SOCKET_TYPE_IS_DGRAM(allocation->socket_type)){
+ tnet_stun_response_t *response = tnet_stun_send_unreliably(allocation->localFD, 500, 7, request, (struct sockaddr*)&allocation->server);
+ if(response)
+ {
+ if(TNET_STUN_RESPONSE_IS_ERROR(response)){
+ short code = tnet_stun_message_get_errorcode(response);
+ const char* realm = tnet_stun_message_get_realm(response);
+ const char* nonce = tnet_stun_message_get_nonce(response);
+
+ if(code == 401 && realm && nonce){
+ if(!allocation->nonce)
+ { /* First time we get a nonce */
+ tsk_strupdate(&allocation->nonce, nonce);
+ tsk_strupdate(&allocation->realm, realm);
+
+ /* Delete the message and response before retrying*/
+ TSK_OBJECT_SAFE_FREE(response);
+ TSK_OBJECT_SAFE_FREE(request);
+
+ // Send again using new transaction identifier
+ return tnet_turn_send_request(context, allocation, funcptr);
+ }
+ else{
+ ret = -3;
+ }
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("Server error code: %d", code);
+ ret = -2;
+ }
+ }
+ else /* Any (allocate, permission, channel binding ...) success response */
+ {
+ if(response->type = stun_allocate_success_response) /* Allocate success response */
+ {
+ /* LifeTime */
+ {
+ int32_t lifetime = tnet_stun_message_get_lifetime(response);
+ if(lifetime>=0)
+ {
+ allocation->timeout = lifetime;
+ }
+ }
+ /* STUN mapped or xmapped address */
+ {
+ const tnet_stun_attribute_t *attribute;
+ if((attribute = tnet_stun_message_get_attribute(response, stun_xor_mapped_address)))
+ {
+ allocation->xmaddr = tsk_object_ref((void*)attribute);
+ }
+ else if((attribute= tnet_stun_message_get_attribute(response, stun_mapped_address)))
+ {
+ allocation->maddr = tsk_object_ref((void*)attribute);
+ }
+ }
+ }
+
+ /* Set ret to zero (success) */
+ ret = 0;
+ }
+ }
+ else{
+ ret = -4;
+ }
+ TSK_OBJECT_SAFE_FREE(response);
+ }
+ }
+
+ TSK_OBJECT_SAFE_FREE(request);
+ return ret;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_turn_allocation_id_t tnet_turn_allocate(const tnet_nat_context_t* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type)
+{
+ tnet_turn_allocation_id_t id = TNET_TURN_INVALID_ALLOCATION_ID;
+
+ if(nat_context){
+ int ret;
+ tnet_turn_allocation_t* allocation = tnet_turn_allocation_create(localFD, nat_context->socket_type, nat_context->server_address, nat_context->server_port, nat_context->username, nat_context->password);
+ allocation->software = tsk_strdup(nat_context->software);
+
+ if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_allocate))){
+ TSK_DEBUG_ERROR("TURN allocation failed with error code:%d.", ret);
+ TSK_OBJECT_SAFE_FREE(allocation);
+ }
+ else{
+ id = allocation->id;
+ tsk_list_push_back_data(nat_context->allocations, (void**)&allocation);
+ }
+ }
+
+ return id;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_allocation_refresh(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation)
+{
+ if(nat_context && allocation){
+ int ret;
+
+ if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_refresh))){
+ TSK_DEBUG_ERROR("TURN allocation refresh failed with error code:%d.", ret);
+ return -1;
+ }
+ else{
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_unallocate(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation)
+{
+ if(nat_context && allocation){
+ int ret;
+
+ if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_unallocate))){
+ TSK_DEBUG_ERROR("TURN unallocation failed with error code:%d.", ret);
+ return -1;
+ }
+ else{
+ tsk_list_remove_item_by_data(nat_context->allocations, allocation);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer)
+{
+ tnet_turn_channel_binding_id_t id = TNET_TURN_INVALID_CHANNEL_BINDING_ID;
+ tnet_turn_channel_binding_t *channel_binding = 0;
+
+ if(nat_context && allocation){
+ int ret;
+
+ channel_binding = tnet_turn_channel_binding_create(allocation);
+
+ if(channel_binding){
+ if(((struct sockaddr*)peer)->sa_family == AF_INET){
+ struct sockaddr_in *sin = ((struct sockaddr_in*)peer);
+ uint32_t _sin_addr;
+
+ channel_binding->xpeer = tnet_turn_attribute_xpeer_addr_create_null();
+ channel_binding->xpeer->family = stun_ipv4;
+ channel_binding->xpeer->xport = ((sin->sin_port) ^ tnet_htons(0x2112));
+
+ _sin_addr = tnet_htonl_2(&sin->sin_addr) ^tnet_htonl(TNET_STUN_MAGIC_COOKIE);
+ memcpy(channel_binding->xpeer->xaddress, &_sin_addr, sizeof(_sin_addr));
+ }
+ else if(((struct sockaddr*)peer)->sa_family == AF_INET6){
+ TSK_DEBUG_ERROR("IPv6 not supported.");
+ goto bail;
+ }
+ else{
+ TSK_DEBUG_ERROR("Invalid address family.");
+ goto bail;
+ }
+ }
+ else{
+ goto bail;
+ }
+
+ if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_channel_bind, channel_binding))){
+ TSK_DEBUG_ERROR("TURN (CHANNEL-BIND) failed with error code:%d.", ret);
+ TSK_OBJECT_SAFE_FREE(channel_binding);
+
+ goto bail;
+ }
+ else{
+ id = channel_binding->id;
+ tsk_list_push_back_data(allocation->channel_bindings, (void**)&channel_binding);
+ }
+ }
+
+bail:
+ TSK_OBJECT_SAFE_FREE(channel_binding);
+ return id;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_channel_refresh(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind)
+{
+ if(nat_context && channel_bind){
+ int ret;
+
+ if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_channel_refresh, channel_bind))){
+ TSK_DEBUG_ERROR("TURN channel-binding refresh failed with error code:%d.", ret);
+ return -1;
+ }
+ else return 0;
+ }
+ return -1;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_channel_senddata(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication)
+{
+ tnet_turn_channel_data_t *channel_data = 0;
+ tsk_buffer_t *output = 0;
+
+ int ret = -1;
+
+ if(nat_context && channel_bind)
+ {
+ if(indication)
+ { /* SEND INDICATION */
+ if((ret = tnet_turn_send_request(nat_context, (tnet_turn_allocation_t*)channel_bind->allocation, tnet_turn_create_request_sendindication, channel_bind->xpeer, data, size)))
+ {
+ TSK_DEBUG_ERROR("TURN channel send indication failed with error code:%d.", ret);
+ return -1;
+ }
+ else return 0;
+ }
+ else
+ { /* CHANNEL DATA */
+ if(!(channel_data = tnet_turn_channel_data_create(channel_bind->id, size, data)))
+ {
+ TSK_DEBUG_ERROR("Failed to create TURN CHANNEL-DATA message.");
+ goto bail;
+ }
+
+ if(!(output = tnet_turn_channel_data_serialize(channel_data)))
+ {
+ TSK_DEBUG_ERROR("Failed to serialize TURN CHANNEL-DATA.");
+ goto bail;
+ }
+
+ if(tnet_sockfd_sendto(channel_bind->allocation->localFD, (struct sockaddr*)&channel_bind->allocation->server, output->data, output->size) <= 0)
+ {
+ TNET_PRINT_LAST_ERROR("Failed to send TURN messsage.");
+ ret = -2;
+ goto bail;
+ }
+ else
+ {
+ ret = 0;
+ }
+ }
+ }
+bail:
+ TSK_OBJECT_SAFE_FREE(channel_data);
+ TSK_OBJECT_SAFE_FREE(output);
+
+ return ret;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_add_permission(const tnet_nat_context_t* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout)
+{
+ if(nat_context && allocation)
+ {
+ int ret;
+
+ if((ret = tnet_turn_send_request(nat_context, allocation, tnet_turn_create_request_permission, ipaddress)))
+ {
+ TSK_DEBUG_ERROR("TURN (ADD) permission failed with error code:%d.", ret);
+ return -1;
+ }
+ else
+ {
+ //tnet_turn_permission_t *permission = tnet_turn_permission_create(timeout);
+ //tsk_list_remove_item_by_data(context->allocations, allocation);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+//=================================================================================================
+// TURN CHANNEL-BINDING object definition
+//
+static tsk_object_t* tnet_turn_channel_binding_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_channel_binding_t *channel_binding = self;
+ if(channel_binding){
+ static tnet_turn_channel_binding_id_t __allocation_unique_id = 0x4000; /* 0x4000 through 0x7FFF */
+
+ channel_binding->id = __allocation_unique_id++;
+ channel_binding->allocation = va_arg(*app, const tnet_turn_allocation_t *);
+ channel_binding->timeout = TNET_TURN_CHANBIND_TIMEOUT_DEFAULT; /* 10 minutes as per draft-ietf-behave-turn-16 subclause 11 */
+
+ if(__allocation_unique_id >= 0x7FFF){
+ __allocation_unique_id = 0x4000;
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_channel_binding_dtor(tsk_object_t * self)
+{
+ tnet_turn_channel_binding_t *channel_binding = self;
+ if(channel_binding){
+ TSK_OBJECT_SAFE_FREE(channel_binding->xpeer);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_channel_binding_def_s =
+{
+ sizeof(tnet_turn_channel_binding_t),
+ tnet_turn_channel_binding_ctor,
+ tnet_turn_channel_binding_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_channel_binding_def_t = &tnet_turn_channel_binding_def_s;
+
+//=================================================================================================
+// TURN PERMISSION object definition
+//
+static tsk_object_t* tnet_turn_permission_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_permission_t *permission = self;
+ if(permission){
+ permission->timeout = va_arg(*app, uint32_t);
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_permission_dtor(tsk_object_t * self)
+{
+ tnet_turn_permission_t *permission = self;
+ if(permission){
+ TSK_OBJECT_SAFE_FREE(permission->xpeer);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_permission_def_s =
+{
+ sizeof(tnet_turn_permission_t),
+ tnet_turn_permission_ctor,
+ tnet_turn_permission_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_permission_def_t = &tnet_turn_permission_def_s;
+
+
+
+//=================================================================================================
+// TURN ALLOCATION object definition
+//
+static tsk_object_t* tnet_turn_allocation_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_allocation_t *allocation = self;
+ if(allocation){
+ static tnet_turn_allocation_id_t __allocation_unique_id = 0;
+
+ const char* server_address;
+ tnet_port_t server_port;
+
+ allocation->id = ++__allocation_unique_id;
+
+ allocation->localFD = va_arg(*app, tnet_fd_t);
+ allocation->socket_type = va_arg(*app, tnet_socket_type_t);
+
+ server_address = va_arg(*app, const char*);
+#if defined(__GNUC__)
+ server_port = (tnet_port_t)va_arg(*app, unsigned);
+#else
+ server_port = va_arg(*app, tnet_port_t);
+#endif
+
+ allocation->username = tsk_strdup(va_arg(*app, const char*));
+ allocation->password = tsk_strdup(va_arg(*app, const char*));
+
+ tnet_sockaddr_init(server_address, server_port, allocation->socket_type, &allocation->server);
+ allocation->timeout = 600;
+
+ allocation->channel_bindings = tsk_list_create();
+ allocation->permissions = tsk_list_create();
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_allocation_dtor(tsk_object_t * self)
+{
+ tnet_turn_allocation_t *allocation = self;
+ if(allocation){
+ TSK_FREE(allocation->relay_address);
+
+ TSK_FREE(allocation->username);
+ TSK_FREE(allocation->password);
+ TSK_FREE(allocation->realm);
+ TSK_FREE(allocation->nonce);
+
+ TSK_FREE(allocation->software);
+
+ TSK_OBJECT_SAFE_FREE(allocation->xmaddr);
+ TSK_OBJECT_SAFE_FREE(allocation->maddr);
+
+ TSK_OBJECT_SAFE_FREE(allocation->channel_bindings);
+ TSK_OBJECT_SAFE_FREE(allocation->permissions);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_allocation_def_s =
+{
+ sizeof(tnet_turn_allocation_t),
+ tnet_turn_allocation_ctor,
+ tnet_turn_allocation_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_allocation_def_t = &tnet_turn_allocation_def_s;
+
diff --git a/tinyNET/src/turn/tnet_turn.h b/tinyNET/src/turn/tnet_turn.h
new file mode 100644
index 0000000..0a43207
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn.h
@@ -0,0 +1,175 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn.h
+ * @brief Traversal Using Relays around NAT (TURN) implementation as per 'draft-ietf-behave-turn-16', 'draft-ietf-behave-turn-tcp-05'
+ * and 'draft-ietf-behave-turn-ipv6'.
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-16
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-tcp-05
+ * http://tools.ietf.org/html/draft-ietf-behave-turn-ipv6-07
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_H
+#define TNET_TURN_H
+
+#include "tinynet_config.h"
+
+#include "turn/tnet_turn_attribute.h"
+
+#include "tnet_proto.h"
+#include "tnet_socket.h"
+#include "tnet_types.h"
+
+#include "tsk_object.h"
+
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_PERMISSION_TIMEOUT_DEFAULT
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_CHANBIND_TIMEOUT_DEFAULT
+*/
+TNET_BEGIN_DECLS
+
+#define TNET_TURN_PERMISSION_TIMEOUT_DEFAULT 300 /* draft-ietf-behave-turn-16 subclause 8 */
+#define TNET_TURN_CHANBIND_TIMEOUT_DEFAULT 600 /* draft-ietf-behave-turn-16 subclause 11 */
+
+
+/**@ingroup tnet_turn_group
+* @def tnet_turn_allocation_id_t.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_INVALID_ALLOCATION_ID.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_IS_VALID_ALLOCATION_ID.
+*/
+typedef uint64_t tnet_turn_allocation_id_t;
+#define TNET_TURN_INVALID_ALLOCATION_ID 0
+#define TNET_TURN_IS_VALID_ALLOCATION_ID(id) (id != TNET_TURN_INVALID_ALLOCATION_ID)
+
+/**@ingroup tnet_turn_group
+* @def tnet_turn_channel_binding_id_t.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_INVALID_CHANNEL_BINDING_ID.
+*/
+/**@ingroup tnet_turn_group
+* @def TNET_TURN_IS_VALID_CHANNEL_BINDING_ID.
+*/
+typedef uint16_t tnet_turn_channel_binding_id_t;
+#define TNET_TURN_INVALID_CHANNEL_BINDING_ID 0x00
+#define TNET_TURN_IS_VALID_CHANNEL_BINDING_ID(id) ( (0x4000 <= id) && (id <= 0x7FFF) ) /* see draft-ietf-behave-turn-16 subcaluse 11. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_permission_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_attribute_xpeer_addr_t *xpeer;
+ uint32_t timeout; /**< Timeout value in seconds. Default is 300s(5 minutes). */
+}
+tnet_turn_permission_t;
+typedef tsk_list_t tnet_turn_permissions_L_t; /**< List of @ref tnet_turn_permission_t elements. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_channel_binding_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_channel_binding_id_t id;
+ const struct tnet_turn_allocation_s *allocation;
+ tnet_turn_attribute_xpeer_addr_t *xpeer;
+ uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+}
+tnet_turn_channel_binding_t;
+typedef tsk_list_t tnet_turn_channel_bindings_L_t; /**< List of @ref tnet_turn_channel_binding_t elements. */
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_allocation_s
+{
+ TSK_DECLARE_OBJECT;
+
+ tnet_turn_allocation_id_t id; /**< Unique id. */
+
+ char* relay_address; /**< the relayed transport address */
+ //! Server reflexive address of the local socket(STUN1 as per RFC 3489).
+ tnet_stun_attribute_mapped_addr_t *maddr;
+ //! XORed server reflexive address (STUN2 as per RFC 5389).
+ tnet_stun_attribute_xmapped_addr_t *xmaddr;
+
+ /* 5-tuple */
+ tnet_fd_t localFD;
+ tnet_socket_type_t socket_type;
+
+ struct sockaddr_storage server;
+
+ /*---*/
+
+ /* the authentication information */
+ char* username;
+ char* password;
+ char* realm;
+ char* nonce;
+ /*---*/
+
+ /* the time-to-expiry */
+ uint32_t timeout; /**< Timeout value in seconds. Default is 600s(10 minutes). */
+ /*---*/
+
+ /* A list of permissions */
+ /* A list of channel to peer bindings */
+
+ char* software;
+
+ tnet_turn_channel_bindings_L_t *channel_bindings;
+ tnet_turn_permissions_L_t *permissions;
+}
+tnet_turn_allocation_t;
+typedef tsk_list_t tnet_turn_allocations_L_t; /**< List of @ref tnet_turn_allocation_t elements. */
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_permission_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_binding_def_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_allocation_def_t;
+
+//#if defined(__SYMBIAN32__) || ANDROID /* Forward declaration */
+struct tnet_nat_context_s;
+//#endif
+
+tnet_turn_allocation_id_t tnet_turn_allocate(const struct tnet_nat_context_s* nat_context, const tnet_fd_t localFD, tnet_socket_type_t socket_type);
+int tnet_turn_allocation_refresh(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation);
+int tnet_turn_unallocate(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation);
+tnet_turn_channel_binding_id_t tnet_turn_channel_bind(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation, struct sockaddr_storage *peer);
+int tnet_turn_channel_refresh(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind);
+int tnet_turn_channel_senddata(const struct tnet_nat_context_s* nat_context, const tnet_turn_channel_binding_t * channel_bind, const void* data, tsk_size_t size, int indication);
+int tnet_turn_add_permission(const struct tnet_nat_context_s* nat_context, tnet_turn_allocation_t *allocation, const char* ipaddress, uint32_t timeout);
+
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_H */
+
diff --git a/tinyNET/src/turn/tnet_turn_attribute.c b/tinyNET/src/turn/tnet_turn_attribute.c
new file mode 100644
index 0000000..0bc55ad
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.c
@@ -0,0 +1,649 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn_attribute.c
+ * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_turn_attribute.h"
+
+#include "../stun/tnet_stun.h"
+
+#include "../tnet_endianness.h"
+
+#include "tsk_debug.h"
+
+#include <string.h>
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number)
+{
+ return tsk_object_new(tnet_turn_attribute_channelnum_def_t, number);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime)
+{
+ return tsk_object_new(tnet_turn_attribute_lifetime_def_t, lifetime);
+}
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_xpeer_addr_def_t, payload, payload_size);
+}
+
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null()
+{
+ return tnet_turn_attribute_xpeer_addr_create(tsk_null, 0);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.4. DATA */
+tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_data_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_xrelayed_addr_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R)
+{
+ return tsk_object_new(tnet_turn_attribute_even_port_def_t, R);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol)
+{
+ return tsk_object_new(tnet_turn_attribute_reqtrans_def_t, protocol);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create()
+{
+ return tsk_object_new(tnet_turn_attribute_dontfrag_def_t);
+}
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size)
+{
+ return tsk_object_new(tnet_turn_attribute_restoken_def_t, payload, payload_size);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tnet_stun_attribute_t* tnet_turn_attribute_deserialize(tnet_stun_attribute_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size)
+{
+ tnet_stun_attribute_t *attribute = tsk_null;
+ const uint8_t* dataPtr = payload;
+
+ /* Attribute Value
+ */
+
+ switch(type)
+ {
+ /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+ case stun_channel_number:
+ {
+ uint32_t number = tnet_htonl_2(dataPtr);
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_channelnum_create(number);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+ case stun_lifetime:
+ {
+ uint32_t lifetime = tnet_htonl_2(dataPtr);
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_lifetime_create(lifetime);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+ case stun_xor_peer_address:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.4. DATA */
+ case stun_data:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+ case stun_xor_relayed_address:
+ {
+ attribute = (tnet_stun_attribute_t *)tnet_turn_attribute_xrelayed_addr_create(dataPtr, length);
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+ case stun_even_port:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+ case stun_requested_transport:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+ case stun_dont_fragment:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+ case stun_reservation_token:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+
+ default:
+ {
+ TSK_DEBUG_ERROR("==> NOT IMPLEMENTED");
+ break;
+ }
+ }
+
+ if(!attribute){
+ /* Create default */
+ attribute = tnet_stun_attribute_create();
+ }
+
+ return attribute;
+}
+
+/**@ingroup tnet_turn_group
+*/
+int tnet_turn_attribute_serialize(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output)
+{
+ if(!attribute || !output){
+ return -1;
+ }
+
+ /* Attribute Value
+ */
+
+ switch(attribute->type){
+ /* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER */
+ case stun_channel_number:
+ {
+ tnet_turn_attribute_channelnum_t *number = (tnet_turn_attribute_channelnum_t*)attribute;
+ tsk_buffer_append(output, &(number->number), 2);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.2. LIFETIME */
+ case stun_lifetime:
+ {
+ tnet_turn_attribute_lifetime_t *lifetime = (tnet_turn_attribute_lifetime_t*)attribute;
+ tsk_buffer_append(output, &(lifetime->value), 4);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS */
+ case stun_xor_peer_address:
+ {
+ tnet_turn_attribute_xpeer_addr_t* xpeer = (tnet_turn_attribute_xpeer_addr_t*)attribute;
+ if(xpeer){
+ if(xpeer->family == stun_ipv4){
+ uint8_t pad = 0x00;
+ tsk_buffer_append(output, &pad, 1);
+ tsk_buffer_append(output, &xpeer->family, 1);
+ tsk_buffer_append(output, &xpeer->xport, 2);
+ tsk_buffer_append(output, xpeer->xaddress, 4);
+ }
+ else
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:XOR-PEER-ADDRESS ==> IPV6 - NOT IMPLEMENTED");
+ return -3;
+ }
+ }
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.4. DATA */
+ case stun_data:
+ {
+ tnet_turn_attribute_data_t *data = (tnet_turn_attribute_data_t*)attribute;
+ if(data->value){
+ tsk_buffer_append(output, data->value->data, data->value->size);
+ }
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS */
+ case stun_xor_relayed_address:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:XOR-RELAYED-ADDRESS ==> NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT */
+ case stun_even_port:
+ {
+ tnet_turn_attribute_even_port_t *even_port = (tnet_turn_attribute_even_port_t*)attribute;
+ uint8_t value = (even_port->R << 7);
+ tsk_buffer_append(output, &(value), 1);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT */
+ case stun_requested_transport:
+ {
+ tnet_turn_attribute_reqtrans_t *reqtrans = (tnet_turn_attribute_reqtrans_t*)attribute;
+ tsk_buffer_append(output, &(reqtrans->protocol), 1);
+ tsk_buffer_append(output, &(reqtrans->rffu), 3);
+ return 0;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT */
+ case stun_dont_fragment:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:DONT-FRAGMENT ==> NOT IMPLEMENTED");
+ return -3;
+ }
+
+ /* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN */
+ case stun_reservation_token:
+ {
+ TSK_DEBUG_ERROR("SERIALIZE:TOKEN ==> NOT IMPLEMENTED");
+ return -3;
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_channelnum_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_channelnum_t *attribute = self;
+ if(attribute){
+#if defined (__GNUC__)
+ attribute->number = (uint16_t)(va_arg(*app, unsigned));
+#else
+ attribute->number = (va_arg(*app, uint16_t));
+#endif
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_channel_number;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 2;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_channelnum_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_channelnum_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_channelnum_def_s =
+{
+ sizeof(tnet_turn_attribute_channelnum_t),
+ tnet_turn_attribute_channelnum_ctor,
+ tnet_turn_attribute_channelnum_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t = &tnet_turn_attribute_channelnum_def_s;
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.2. LIFETIME]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_lifetime_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_lifetime_t *attribute = self;
+ if(attribute){
+ attribute->value = /*tnet_htonl*/(va_arg(*app, uint32_t));
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_lifetime;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_lifetime_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_lifetime_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_lifetime_def_s =
+{
+ sizeof(tnet_turn_attribute_lifetime_t),
+ tnet_turn_attribute_lifetime_ctor,
+ tnet_turn_attribute_lifetime_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t = &tnet_turn_attribute_lifetime_def_s;
+
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_xpeer_addr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_xpeer_addr_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ }
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_peer_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 8;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_xpeer_addr_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_xpeer_addr_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_xpeer_addr_def_s =
+{
+ sizeof(tnet_turn_attribute_xpeer_addr_t),
+ tnet_turn_attribute_xpeer_addr_ctor,
+ tnet_turn_attribute_xpeer_addr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t = &tnet_turn_attribute_xpeer_addr_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.4. DATA]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_data_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_data_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ attribute->value = tsk_buffer_create(payload, payload_size);
+ }
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_data;
+ TNET_STUN_ATTRIBUTE(attribute)->length = (uint16_t)payload_size;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_data_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_data_t *attribute = self;
+ if(attribute){
+ TSK_OBJECT_SAFE_FREE(attribute->value);
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_data_def_s =
+{
+ sizeof(tnet_turn_attribute_data_t),
+ tnet_turn_attribute_data_ctor,
+ tnet_turn_attribute_data_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_data_def_t = &tnet_turn_attribute_data_def_s;
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_xrelayed_addr_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+ if(attribute){
+ const void *payload = va_arg(*app, const void*);
+ tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ if(payload && payload_size){
+ const uint8_t *payloadPtr = (const uint8_t*)payload;
+ payloadPtr += 1; /* Ignore first 8bits */
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_xor_relayed_address;
+ TNET_STUN_ATTRIBUTE(attribute)->length = payload_size;
+
+ attribute->family = (tnet_stun_addr_family_t)(*(payloadPtr++));
+
+ attribute->xport = tnet_ntohs_2(payloadPtr);
+ attribute->xport ^= 0x2112;
+ payloadPtr+=2;
+
+ { /*=== Compute IP address */
+ tsk_size_t addr_size = (attribute->family == stun_ipv6) ? 16 : (attribute->family == stun_ipv4 ? 4 : 0);
+ if(addr_size){
+ tsk_size_t i;
+ uint32_t addr;
+
+ for(i=0; i<addr_size; i+=4){
+ addr = tnet_htonl_2(payloadPtr);
+ addr ^= TNET_STUN_MAGIC_COOKIE;
+ memcpy(&attribute->xaddress[i], &addr, 4);
+ payloadPtr+=4;
+ }
+ }
+ else{
+ TSK_DEBUG_ERROR("UNKNOWN FAMILY [%u].", attribute->family);
+ }
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_xrelayed_addr_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_xrelayed_addr_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_xrelayed_addr_def_s =
+{
+ sizeof(tnet_turn_attribute_xrelayed_addr_t),
+ tnet_turn_attribute_xrelayed_addr_ctor,
+ tnet_turn_attribute_xrelayed_addr_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t = &tnet_turn_attribute_xrelayed_addr_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.6. EVEN-PORT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_even_port_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_even_port_t *attribute = self;
+ if(attribute){
+ attribute->R = va_arg(*app, unsigned);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_even_port;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 1;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_even_port_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_even_port_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_even_port_def_s =
+{
+ sizeof(tnet_turn_attribute_even_port_t),
+ tnet_turn_attribute_even_port_ctor,
+ tnet_turn_attribute_even_port_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_even_port_def_t = &tnet_turn_attribute_even_port_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_reqtrans_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_reqtrans_t *attribute = self;
+ if(attribute){
+ attribute->protocol = va_arg(*app, tnet_proto_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_requested_transport;
+ TNET_STUN_ATTRIBUTE(attribute)->length = 4;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_reqtrans_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_reqtrans_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_reqtrans_def_s =
+{
+ sizeof(tnet_turn_attribute_reqtrans_t),
+ tnet_turn_attribute_reqtrans_ctor,
+ tnet_turn_attribute_reqtrans_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t = &tnet_turn_attribute_reqtrans_def_s;
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_dontfrag_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_dontfrag_t *attribute = self;
+ if(attribute){
+ //const void *payload = va_arg(*app, const void*);
+ //tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_dont_fragment;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_dontfrag_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_dontfrag_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_dontfrag_def_s =
+{
+ sizeof(tnet_turn_attribute_dontfrag_t),
+ tnet_turn_attribute_dontfrag_ctor,
+ tnet_turn_attribute_dontfrag_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t = &tnet_turn_attribute_dontfrag_def_s;
+
+
+
+//=================================================================================================
+// [[draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN]] object definition
+//
+static tsk_object_t* tnet_turn_attribute_restoken_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_attribute_restoken_t *attribute = self;
+ if(attribute){
+ //--const void *payload = va_arg(*app, const void*);
+ //--tsk_size_t payload_size = va_arg(*app, tsk_size_t);
+
+ TNET_STUN_ATTRIBUTE(attribute)->type = stun_reservation_token;
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_attribute_restoken_dtor(tsk_object_t * self)
+{
+ tnet_turn_attribute_restoken_t *attribute = self;
+ if(attribute){
+ }
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_attribute_restoken_def_s =
+{
+ sizeof(tnet_turn_attribute_restoken_t),
+ tnet_turn_attribute_restoken_ctor,
+ tnet_turn_attribute_restoken_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_attribute_restoken_def_t = &tnet_turn_attribute_restoken_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_attribute.h b/tinyNET/src/turn/tnet_turn_attribute.h
new file mode 100644
index 0000000..8a1915e
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_attribute.h
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn_attribute.h
+ * @brief New STUN Attributes as per draft-ietf-behave-turn-16 subclause 14.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_ATTRIBUTE_H
+#define TNET_TURN_ATTRIBUTE_H
+
+#include "tinynet_config.h"
+#include "tnet_proto.h"
+#include "stun/tnet_stun_attribute.h"
+
+TNET_BEGIN_DECLS
+
+typedef tnet_stun_attribute_t tnet_turn_attribute_t;
+
+/* draft-ietf-behave-turn-16 - 14.1. CHANNEL-NUMBER
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | RFFU = 0 |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_attribute_channelnum_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint16_t number;
+ uint16_t rffu;
+}
+tnet_turn_attribute_channelnum_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_channelnum_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.2. LIFETIME
+*/
+typedef struct tnet_turn_attribute_lifetime_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint32_t value;
+}
+tnet_turn_attribute_lifetime_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_lifetime_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.3. XOR-PEER-ADDRESS
+*/
+typedef struct tnet_turn_attribute_xpeer_addr_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tnet_stun_addr_family_t family;
+ uint16_t xport;
+ uint8_t xaddress[16];
+}
+tnet_turn_attribute_xpeer_addr_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xpeer_addr_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.4. DATA
+*/
+typedef struct tnet_turn_attribute_data_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tsk_buffer_t* value;
+}
+tnet_turn_attribute_data_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_data_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.5. XOR-RELAYED-ADDRESS
+*/
+typedef struct tnet_turn_attribute_xrelayed_addr_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ tnet_stun_addr_family_t family;
+ uint16_t xport;
+ uint8_t xaddress[16];
+}
+tnet_turn_attribute_xrelayed_addr_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_xrelayed_addr_def_t;
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.6. EVEN-PORT
+*/
+typedef struct tnet_turn_attribute_even_port_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+/*
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |R| RFFU |
+ +-+-+-+-+-+-+-+-+
+*/
+ unsigned R:1;
+ unsigned rffu:7;
+}
+tnet_turn_attribute_even_port_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_even_port_def_t;
+
+
+/**@ingroup tnet_turn_group
+*/
+typedef struct tnet_turn_attribute_reqtrans_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+/*
+ draft-ietf-behave-turn-16 - 14.7. REQUESTED-TRANSPORT
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Protocol | RFFU |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+ tnet_proto_t protocol;
+ uint8_t rffu[3];
+}
+tnet_turn_attribute_reqtrans_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_reqtrans_def_t;
+
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.8. DONT-FRAGMENT
+*/
+typedef struct tnet_turn_attribute_dontfrag_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+}
+tnet_turn_attribute_dontfrag_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_dontfrag_def_t;
+
+
+/**@ingroup tnet_turn_group
+* draft-ietf-behave-turn-16 - 14.9. RESERVATION-TOKEN
+*/
+typedef struct tnet_turn_attribute_restoken_s
+{
+ TNET_STUN_DECLARE_ATTRIBUTE;
+
+ uint8_t value[8];
+}
+tnet_turn_attribute_restoken_t;
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_attribute_restoken_def_t;
+
+
+tnet_stun_attribute_t* tnet_turn_attribute_deserialize(tnet_stun_attribute_type_t type, uint16_t length, const void* payload, tsk_size_t payload_size);
+int tnet_turn_attribute_serialize(const tnet_stun_attribute_t* attribute, tsk_buffer_t *output);
+
+tnet_turn_attribute_channelnum_t* tnet_turn_attribute_channelnum_create(uint16_t number);
+tnet_turn_attribute_lifetime_t* tnet_turn_attribute_lifetime_create(uint32_t lifetime);
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_xpeer_addr_t* tnet_turn_attribute_xpeer_addr_create_null();
+tnet_turn_attribute_data_t* tnet_turn_attribute_data_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_xrelayed_addr_t* tnet_turn_attribute_xrelayed_addr_create(const void* payload, tsk_size_t payload_size);
+tnet_turn_attribute_even_port_t* tnet_turn_attribute_even_port_create(unsigned R);
+tnet_turn_attribute_reqtrans_t* tnet_turn_attribute_reqtrans_create(tnet_proto_t protocol);
+tnet_turn_attribute_dontfrag_t* tnet_turn_attribute_dontfrag_create();
+tnet_turn_attribute_restoken_t* tnet_turn_attribute_restoken_create(const void* payload, tsk_size_t payload_size);
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_ATTRIBUTE_H */
+
diff --git a/tinyNET/src/turn/tnet_turn_message.c b/tinyNET/src/turn/tnet_turn_message.c
new file mode 100644
index 0000000..90372c3
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.c
@@ -0,0 +1,170 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn_message.c
+ * @brief Traversal Using Relays around NAT (TURN) messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#include "tnet_turn_message.h"
+
+#include "../tnet_types.h"
+#include "../tnet_endianness.h"
+
+#include "tsk_memory.h"
+
+#include <string.h>
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data)
+{
+ return tsk_object_new(tnet_turn_channel_data_def_t, number, length, data);
+}
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create_null()
+{
+ return tnet_turn_channel_data_create(0, 0, tsk_null);
+}
+
+/**@ingroup tnet_turn_group
+*/
+tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message)
+{
+ tsk_buffer_t *output = 0;
+
+ if(!message) goto bail;
+
+ output = tsk_buffer_create_null();
+
+ /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / Application Data /
+ / /
+ | |
+ | +-------------------------------+
+ | |
+ +-------------------------------+
+ */
+
+ /* Channel Number
+ */
+ {
+ uint16_t number = tnet_htons(message->chanel_number);
+ tsk_buffer_append(output, &(number), 2);
+ }
+
+ /* Length
+ */
+ {
+ uint16_t length = tnet_htons(message->length);
+ tsk_buffer_append(output, &(length), 2);
+ }
+
+ /* Application Data
+ */
+ {
+ tsk_buffer_append(output, message->data, message->length);
+
+ /* === Padding:
+ Over stream transports, the ChannelData message MUST be padded to a
+ multiple of four bytes in order to ensure the alignment of subsequent
+ messages. The padding is not reflected in the length field of the
+ ChannelData message, so the actual size of a ChannelData message
+ (including padding) is (4 + Length) rounded up to the nearest
+ multiple of 4. Over UDP, the padding is not required but MAY be included.
+ */
+ if(message->length%4)
+ {
+ static uint32_t zeros = 0x00000000;
+ tsk_buffer_append(output, &zeros, 4-(message->length%4));
+ }
+ }
+
+bail:
+ return output;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//=================================================================================================
+// TURN CHANNEL-DATA message object definition
+//
+static tsk_object_t* tnet_turn_channel_data_ctor(tsk_object_t * self, va_list * app)
+{
+ tnet_turn_channel_data_t *message = self;
+ if(message){
+ const void* data;
+
+#if defined(__GNUC__)
+ message->chanel_number = (uint16_t)va_arg(*app, unsigned);
+ message->length = (uint16_t)va_arg(*app, unsigned);
+#else
+ message->chanel_number = va_arg(*app, uint16_t);
+ message->length = va_arg(*app, uint16_t);
+#endif
+ data = va_arg(*app, const void*);
+
+ if(data && message->length){
+ if((message->data = tsk_calloc(message->length, sizeof(uint8_t)))){
+ memcpy(message->data, data, message->length);
+ }
+ }
+ }
+ return self;
+}
+
+static tsk_object_t* tnet_turn_channel_data_dtor(tsk_object_t * self)
+{
+ tnet_turn_channel_data_t *message = self;
+ if(message){
+ TSK_FREE(message->data);
+ }
+
+ return self;
+}
+
+static const tsk_object_def_t tnet_turn_channel_data_def_s =
+{
+ sizeof(tnet_turn_channel_data_t),
+ tnet_turn_channel_data_ctor,
+ tnet_turn_channel_data_dtor,
+ tsk_null,
+};
+const tsk_object_def_t *tnet_turn_channel_data_def_t = &tnet_turn_channel_data_def_s;
diff --git a/tinyNET/src/turn/tnet_turn_message.h b/tinyNET/src/turn/tnet_turn_message.h
new file mode 100644
index 0000000..1bd1714
--- /dev/null
+++ b/tinyNET/src/turn/tnet_turn_message.h
@@ -0,0 +1,75 @@
+/*
+* Copyright (C) 2009-2010 Mamadou Diop.
+*
+* Contact: Mamadou Diop <diopmamadou(at)doubango.org>
+*
+* This file is part of Open Source Doubango Framework.
+*
+* DOUBANGO is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* DOUBANGO is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with DOUBANGO.
+*
+*/
+
+/**@file tnet_turn_message.h
+ * @brief Traversal Using Relays around NAT (TURN) messages.
+ *
+ * @author Mamadou Diop <diopmamadou(at)doubango.org>
+ *
+ * @date Created: Sat Nov 8 16:54:58 2009 mdiop
+ */
+#ifndef TNET_TURN_MESSAGE_H
+#define TNET_TURN_MESSAGE_H
+
+#include "../tinynet_config.h"
+
+#include "tsk_buffer.h"
+
+TNET_BEGIN_DECLS
+
+/**@ingroup tnet_turn_group
+ * TURN channel data message as per draft-ietf-behave-turn-16 subclause 11.4.
+*/
+typedef struct tnet_turn_channel_data_s
+{
+ TSK_DECLARE_OBJECT;
+
+ /* draft-ietf-behave-turn-16 11.4. The ChannelData Message
+ 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Channel Number | Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ / Application Data /
+ / /
+ | |
+ | +-------------------------------+
+ | |
+ +-------------------------------+
+ */
+ uint16_t chanel_number;
+ uint16_t length;
+ void* data;
+}
+tnet_turn_channel_data_t;
+
+tsk_buffer_t* tnet_turn_channel_data_serialize(const tnet_turn_channel_data_t *message);
+
+tnet_turn_channel_data_t* tnet_turn_channel_data_create(uint16_t number, uint16_t length, const void* data);
+tnet_turn_channel_data_t* tnet_turn_channel_data_create_null();
+
+TINYNET_GEXTERN const tsk_object_def_t *tnet_turn_channel_data_def_t;
+
+TNET_END_DECLS
+
+#endif /* TNET_TURN_MESSAGE_H */
OpenPOWER on IntegriCloud