doubango/tinyNET/src/stun/tnet_stun_utils.c
c732d49e
 #if HAVE_CRT
 #define _CRTDBG_MAP_ALLOC 
 #include <stdlib.h> 
 #include <crtdbg.h>
 #endif //HAVE_CRT
 /*
74ca6d11
 * Copyright (C) 2020, University of the Basque Country (UPV/EHU)
c732d49e
 * Contact for licensing options: <licensing-mcpttclient(at)mcopenplatform(dot)com>
 *
 * The original file was part of Open Source Doubango Framework
 * Copyright (C) 2010-2011 Mamadou Diop.
 * Copyright (C) 2012 Doubango Telecom <http://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 "stun/tnet_stun_utils.h"
 #include "stun/tnet_stun_pkt.h"
 #include "stun/tnet_stun_attr.h"
 
 #include "tnet_utils.h"
 
 #include "tsk_memory.h"
 #include "tsk_debug.h"
 
 int tnet_stun_utils_inet_pton(tsk_bool_t b_v6, const char* p_src, tnet_stun_addr_t* p_dst)
 {
     int ret;
     if (!p_src || !p_dst) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if ((ret = tnet_inet_pton(b_v6 ? AF_INET6 : AF_INET, p_src, *p_dst) != 1)) { // success == 1
         TSK_DEBUG_ERROR("tnet_inet_pton() with error code = %d", ret);
         return -3;
     }
     return 0;
 }
 
 int tnet_stun_utils_inet_ntop(tsk_bool_t b_v6, const tnet_stun_addr_t* pc_src, tnet_ip_t* p_dst)
 {
     if (!pc_src || !p_dst) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     if (tnet_inet_ntop(b_v6 ? AF_INET6 : AF_INET, *pc_src, *p_dst, sizeof(*p_dst)) == tsk_null) {
         TSK_DEBUG_ERROR("tnet_inet_ntop() failed");
         return -2;
     }
     return 0;
 }
 
 int tnet_stun_utils_transac_id_rand(tnet_stun_transac_id_t* p_transac_id)
 {
     tsk_size_t u;
     static tsk_size_t __u_size = sizeof(tnet_stun_transac_id_t);
     static long __l_chan_num = 0;
 
     tsk_atomic_inc(&__l_chan_num);
 
     if (!p_transac_id) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     for (u = 0; (u < __u_size) && (u < sizeof(long)); ++u) {
         *(((uint8_t*)p_transac_id) + u) = (__l_chan_num >> (u << 3)) & 0xFF;
     }
     for (u = sizeof(long); u < __u_size; ++u) {
         *(((uint8_t*)p_transac_id) + u) = rand() % 0xFF;
     }
     return 0;
 }
 
 int tnet_stun_utils_buff_cmp(const uint8_t* pc_buf1_ptr, tsk_size_t n_buff1_size, const uint8_t* pc_buf2_ptr, tsk_size_t n_buff2_size)
 {
     int ret;
     tsk_size_t u;
     if (!pc_buf1_ptr || !pc_buf2_ptr || (n_buff1_size != n_buff2_size)) {
         return -1;
     }
     for (u = 0; u < n_buff1_size; ++u) {
         if ((ret = (pc_buf1_ptr[u] - pc_buf2_ptr[u]))) {
             return ret;
         }
     }
     return 0;
 }
 
 int tnet_stun_utils_send_unreliably(tnet_fd_t localFD, uint16_t RTO, uint16_t Rc, const struct tnet_stun_pkt_s* pc_stun_req, struct sockaddr* p_addr_server, struct tnet_stun_pkt_s** pp_stun_resp)
 {
     int ret = -1;
     uint16_t i, rto = RTO;
     struct timeval tv;
     fd_set set;
     void* p_buff_ptr = tsk_null;
     tsk_size_t u_buff_size;
 
     if (!pc_stun_req || !p_addr_server || !pp_stun_resp) {
         TSK_DEBUG_ERROR("Invalid parameter");
         return -1;
     }
     /*	RFC 5389 - 7.2.1.  Sending over UDP
     STUN indications are not retransmitted; thus, indication transactions over UDP
     are not reliable.
     */
     *pp_stun_resp = tsk_null;
     tv.tv_sec = 0;
     tv.tv_usec = 0;
 
     if ((ret = tnet_stun_pkt_get_size_in_octetunits_with_padding(pc_stun_req, &u_buff_size))) {
         goto bail;
     }
     u_buff_size += kStunBuffMinPad;
 	#if HAVE_CRT //Debug memory
 		if (!(p_buff_ptr = malloc(u_buff_size))) {
 	#else
 		if (!(p_buff_ptr = tsk_malloc(u_buff_size))) {
 	#endif //HAVE_CRT
     
         goto bail;
     }
     if ((ret = tnet_stun_pkt_write_with_padding(pc_stun_req, p_buff_ptr, u_buff_size, &u_buff_size))) {
         goto bail;
     }
 
     /*	RFC 5389 - 7.2.1.  Sending over UDP
     	A client SHOULD retransmit a STUN request message starting with an
     	interval of RTO ("Retransmission TimeOut"), doubling after each
     	retransmission.
 
     	e.g. 0 ms, 500 ms, 1500 ms, 3500 ms, 7500ms, 15500 ms, and 31500 ms
     */
     for (i = 0; i < Rc; i++) {
         tv.tv_sec += rto/1000;
         tv.tv_usec += (rto% 1000) * 1000;
         if (tv.tv_usec >= 1000000) {
             tv.tv_usec -= 1000000;
             tv.tv_sec++;
         }
 
         FD_ZERO(&set);
         FD_SET(localFD, &set);
 
         if ((ret = tnet_sockfd_sendto(localFD, p_addr_server, p_buff_ptr, u_buff_size))) {
             // do nothing... not an error
         }
 
         if ((ret = select(localFD+1, &set, NULL, NULL, &tv)) < 0) {
             goto bail;
         }
         else if (ret == 0) {
             /* timeout */
             TSK_DEBUG_INFO("STUN request timedout at %d", i);
             rto *= 2;
             continue;
         }
         else if (FD_ISSET(localFD, &set)) {
             /* there is data to read */
 
             unsigned int len = 0;
             void* data = 0;
 
             TSK_DEBUG_INFO("STUN request got response");
 
             /* Check how how many bytes are pending */
             if ((ret = tnet_ioctlt(localFD, FIONREAD, &len)) < 0) {
                 goto bail;
             }
 
             if(len == 0) {
                 TSK_DEBUG_INFO("tnet_ioctlt() returent zero bytes");
                 continue;
             }
 
             /* Receive pending data */
 			#if HAVE_CRT //Debug memory
 		data = malloc(len);
 			#else
 		data = tsk_malloc(len);
 			#endif //HAVE_CRT
             
             if ((ret = tnet_sockfd_recvfrom(localFD, data, len, 0, p_addr_server)) < 0) {
                 TSK_FREE(data);
 
                 TSK_DEBUG_ERROR("Recv STUN dgrams failed with error code:%d", tnet_geterrno());
                 goto bail;
             }
 
             /* Parse the incoming response. */
             ret = tnet_stun_pkt_read(data, (tsk_size_t)ret, pp_stun_resp);
             TSK_FREE(data);
             if (*pp_stun_resp) {
                 if (tnet_stun_utils_transac_id_cmp((*pp_stun_resp)->transac_id, pc_stun_req->transac_id) != 0) {
                     /* Not same transaction id */
                     TSK_OBJECT_SAFE_FREE(*pp_stun_resp);
                     continue;
                 }
             }
             goto bail;
         }
         else {
             continue;
         }
     }
 
 bail:
     TSK_FREE(p_buff_ptr);
     return (*pp_stun_resp) ? 0 : -4;
 }